aiobungie
A statically typed, asynchronous API wrapper for building clients for Bungie's API in Python.
Getting Started
This is the basic client you probably want you start with.
import aiobungie
client = aiobungie.Client('YOUR_API_KEY', client_secret='KEY', client_id=0)
async def main() -> None:
async with client.rest:
# Search for Destiny 2 memberships.
users = await client.search_users('Crit')
# Iterate over the users and take the first 5 results.
for user in users.take(5):
# Print the user name and their code.
print(f'{user.name} {user.code}')
# aiobungie provides an internal function to run async functions.
# It's equivalent to asyncio.run()
client.run(main()) # or asyncio.run(main())
RESTClient
aiobungie provides a second way to use Bungie's API,
a single RESTClient allows you to make requests and return JSON objects immediately.
This bypasses the need to deserialize and create objects. It also exposes all OAuth2 and manifest methods.
This can be faster for REST apis.
This is considered the core client since aiobungie.Client is built on top of it.
Using the aiobungie.rest property allows direct access to the raw REST client instance.
import aiobungie
import asyncio
client = aiobungie.RESTClient("TOKEN")
async def main() -> None:
async with client as rest:
payload = await rest.fetch_player('Fate怒', 4275)
for membership in payload:
print(membership['membershipId'])
asyncio.run(main())
RESTPool
A REST client pool allows you to acquire multiple RESTClient that share the same state.
This is useful when you want to spawn an instance for each client which shared the same state.
import aiobungie
import asyncio
pool = aiobungie.RESTPool("token")
async def set() -> None:
# Set your ID to access it from other places.
pool.metadata['my_id'] = 4401
async with pool.acquire() as instance:
...
async def fetch() -> None:
my_id: int = pool.metadata['my_id']
async with pool.acquire() as instance: # A different client instance.
my_user = instance.fetch_bungie_user(my_id)
await asyncio.gather(set(), fetch())
When should you use which client?
- Use
Clientwhen you want to build a Chat Bot, Discord Bot, access data as Python classes. - Use
RESTClientwhen you want one TCP session for all clients, access data as JSON payloads. - Use
RESTPoolwhen you're serving a large amount of connections and want to spawn a session for each, access data as JSON payloads. Note that setting up multiple TCP connections can be expensive.
1# MIT License 2# 3# Copyright (c) 2020 - Present nxtlo 4# 5# Permission is hereby granted, free of charge, to any person obtaining a copy 6# of this software and associated documentation files (the "Software"), to deal 7# in the Software without restriction, including without limitation the rights 8# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9# copies of the Software, and to permit persons to whom the Software is 10# furnished to do so, subject to the following conditions: 11# 12# The above copyright notice and this permission notice shall be included in all 13# copies or substantial portions of the Software. 14# 15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21# SOFTWARE. 22 23"""A statically typed, asynchronous API wrapper for building clients for Bungie's API in Python. 24 25Getting Started 26--------------- 27 28This is the basic client you probably want you start with. 29 30```py 31import aiobungie 32 33client = aiobungie.Client('YOUR_API_KEY', client_secret='KEY', client_id=0) 34 35async def main() -> None: 36 async with client.rest: 37 # Search for Destiny 2 memberships. 38 users = await client.search_users('Crit') 39 40 # Iterate over the users and take the first 5 results. 41 for user in users.take(5): 42 # Print the user name and their code. 43 print(f'{user.name} {user.code}') 44 45# aiobungie provides an internal function to run async functions. 46# It's equivalent to asyncio.run() 47client.run(main()) # or asyncio.run(main()) 48``` 49 50RESTClient 51---------- 52 53aiobungie provides a second way to use Bungie's API, 54 55a single `RESTClient` allows you to make requests and return JSON objects immediately. 56 57This bypasses the need to deserialize and create objects. It also exposes all `OAuth2` and `manifest` methods. 58This can be faster for `REST` apis. 59 60This is considered the core client since `aiobungie.Client` is built on top of it. 61Using the `.rest` property allows direct access to the raw REST client instance. 62 63 64```py 65import aiobungie 66import asyncio 67 68client = aiobungie.RESTClient("TOKEN") 69 70async def main() -> None: 71 async with client as rest: 72 payload = await rest.fetch_player('Fate怒', 4275) 73 74 for membership in payload: 75 print(membership['membershipId']) 76 77asyncio.run(main()) 78``` 79 80RESTPool 81-------- 82 83A REST client pool allows you to acquire multiple `RESTClient` that share the same state. 84 85This is useful when you want to spawn an instance for each client which shared the same state. 86 87```py 88import aiobungie 89import asyncio 90 91pool = aiobungie.RESTPool("token") 92 93async def set() -> None: 94 # Set your ID to access it from other places. 95 pool.metadata['my_id'] = 4401 96 async with pool.acquire() as instance: 97 ... 98 99async def fetch() -> None: 100 my_id: int = pool.metadata['my_id'] 101 async with pool.acquire() as instance: # A different client instance. 102 my_user = instance.fetch_bungie_user(my_id) 103 104await asyncio.gather(set(), fetch()) 105``` 106 107## When should you use which client? 108* Use `Client` when you want to build a Chat Bot, Discord Bot, access data as Python classes. 109* Use `RESTClient` when you want one TCP session for all clients, access data as JSON payloads. 110* Use `RESTPool` when you're serving a large amount of connections and want to spawn a session for each, 111access data as JSON payloads. 112Note that setting up multiple TCP connections can be expensive. 113""" 114 115 116from __future__ import annotations 117 118from aiobungie import builders 119from aiobungie import crates 120from aiobungie import interfaces 121from aiobungie import traits 122from aiobungie import typedefs 123from aiobungie import url 124from aiobungie.client import Client 125from aiobungie.error import * 126from aiobungie.internal import iterators 127from aiobungie.internal.assets import Image 128from aiobungie.internal.enums import * 129from aiobungie.internal.factory import Factory 130from aiobungie.internal.iterators import * 131from aiobungie.rest import * 132from aiobungie.undefined import UNDEFINED 133from aiobungie.undefined import UndefinedOr 134from aiobungie.undefined import UndefinedType 135 136from .metadata import __about__ 137from .metadata import __author__ 138from .metadata import __docs__ 139from .metadata import __email__ 140from .metadata import __license__ 141from .metadata import __url__ 142from .metadata import __version__ 143 144# Alias for crate for backwards compatibility. 145crate = crates 146 147# Activity enums 148from .crates.activity import Difficulty 149 150# Components enums 151from .crates.components import ComponentFields 152from .crates.components import ComponentPrivacy 153 154# Entity enums 155from .crates.entity import GatingScope 156from .crates.entity import ObjectiveUIStyle 157from .crates.entity import ValueUIStyle 158 159# Fireteam enums. 160from .crates.fireteams import FireteamActivity 161from .crates.fireteams import FireteamDate 162from .crates.fireteams import FireteamLanguage 163from .crates.fireteams import FireteamPlatform 164 165# Records enums 166from .crates.records import RecordState 167 168__all__ = [mod for mod in dir() if not mod.startswith("_")] # type: ignore
73@attrs.define(auto_exc=True) 74class AiobungieError(RuntimeError): 75 """Base class that all other exceptions inherit from."""
Base class that all other exceptions inherit from.
Inherited Members
- builtins.BaseException
- with_traceback
- args
635@typing.final 636class AmmoType(int, Enum): 637 """AN enum for Detyiny 2 ammo types.""" 638 639 NONE = 0 640 PRIMARY = 1 641 SPECIAL = 2 642 HEAVY = 3
AN enum for Detyiny 2 ammo types.
163@attrs.define(auto_exc=True) 164class BadRequest(HTTPError): 165 """An exception raised when requesting a resource with the provided data is wrong.""" 166 167 url: typing.Optional[typedefs.StrOrURL] 168 """The URL/endpoint caused this error.""" 169 170 body: typing.Any 171 """The response body.""" 172 173 headers: multidict.CIMultiDictProxy[str] 174 """The response headers.""" 175 176 http_status: http.HTTPStatus = attrs.field( 177 default=http.HTTPStatus.BAD_REQUEST, init=False 178 )
An exception raised when requesting a resource with the provided data is wrong.
2def __init__(self, message, url, body, headers): 3 self.message = message 4 self.url = url 5 self.body = body 6 self.headers = headers 7 self.http_status = attr_dict['http_status'].default 8 BaseException.__init__(self, self.message,self.url,self.body,self.headers)
Method generated by attrs for class BadRequest.
690@typing.final 691class ClanMemberType(int, Enum): 692 """An enum for bungie clan member types.""" 693 694 NONE = 0 695 BEGINNER = 1 696 MEMBER = 2 697 ADMIN = 3 698 ACTING_FOUNDER = 4 699 FOUNDER = 5
An enum for bungie clan member types.
466@typing.final 467class Class(int, Enum): 468 """An Enum for Destiny character classes.""" 469 470 TITAN = 0 471 HUNTER = 1 472 WARLOCK = 2 473 UNKNOWN = 3
An Enum for Destiny character classes.
60class Client(traits.ClientApp): 61 """Standard Bungie API client application. 62 63 This client deserialize the REST JSON responses using `aiobungie.internal.factory.Factory` 64 and returns `aiobungie.crates` Python object implementations of the responses. 65 66 A `aiobungie.RESTClient` REST client can also be used alone for low-level concepts. 67 68 Example 69 ------- 70 ```py 71 import aiobungie 72 73 client = aiobungie.Client('...') 74 75 async def main(): 76 async with client.rest: 77 user = await client.fetch_current_user_memberships('...') 78 print(user) 79 ``` 80 81 Parameters 82 ----------- 83 token: `str` 84 Your Bungie's API key or Token from the developer's portal. 85 86 Other Parameters 87 ---------------- 88 max_retries : `int` 89 The max retries number to retry if the request hit a `5xx` status code. 90 client_secret : `str | None` 91 An optional application client secret, 92 This is only needed if you're fetching OAuth2 tokens with this client. 93 client_id : `int | None` 94 An optional application client id, 95 This is only needed if you're fetching OAuth2 tokens with this client. 96 """ 97 98 __slots__ = ("_rest", "_factory") 99 100 def __init__( 101 self, 102 token: str, 103 /, 104 *, 105 client_secret: typing.Optional[str] = None, 106 client_id: typing.Optional[int] = None, 107 dumps: typedefs.Dumps = helpers.dumps, 108 loads: typedefs.Loads = helpers.loads, 109 max_retries: int = 4, 110 ) -> None: 111 self._rest = rest_.RESTClient( 112 token, 113 dumps=dumps, 114 loads=loads, 115 client_secret=client_secret, 116 client_id=client_id, 117 max_retries=max_retries, 118 ) 119 120 self._factory = factory_.Factory(self) 121 122 @property 123 def factory(self) -> factory_.Factory: 124 return self._factory 125 126 @property 127 def rest(self) -> interfaces.RESTInterface: 128 return self._rest 129 130 @property 131 def request(self) -> Client: 132 return self 133 134 @property 135 def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]: 136 return self._rest.metadata 137 138 def run( 139 self, future: collections.Coroutine[typing.Any, None, None], debug: bool = False 140 ) -> None: 141 loop: typing.Final[asyncio.AbstractEventLoop] = helpers.get_or_make_loop() 142 try: 143 if not loop.is_running(): 144 loop.set_debug(debug) 145 loop.run_until_complete(future) 146 147 except Exception as exc: 148 raise RuntimeError(f"Failed to run {future.__qualname__}") from exc 149 150 except KeyboardInterrupt: 151 _LOG.warn("Unexpected Keyboard interrupt. Exiting.") 152 return 153 154 # * User methods. 155 156 async def fetch_current_user_memberships(self, access_token: str, /) -> user.User: 157 """Fetch and return a user object of the bungie net user associated with account. 158 159 .. warning:: 160 This method requires OAuth2 scope and a Bearer access token. 161 162 Parameters 163 ---------- 164 access_token : `str` 165 A valid Bearer access token for the authorization. 166 167 Returns 168 ------- 169 `aiobungie.crates.user.User` 170 A user object includes the Destiny memberships and Bungie.net user. 171 """ 172 resp = await self.rest.fetch_current_user_memberships(access_token) 173 174 return self.factory.deserialize_user(resp) 175 176 async def fetch_bungie_user(self, id: int, /) -> user.BungieUser: 177 """Fetch a Bungie user by their BungieNet id. 178 179 .. note:: 180 This returns a Bungie user membership only. Take a look at `Client.fetch_membership_from_id` 181 for other memberships. 182 183 Parameters 184 ---------- 185 id: `int` 186 The user id. 187 188 Returns 189 ------- 190 `aiobungie.crates.user.BungieUser` 191 A Bungie user. 192 193 Raises 194 ------ 195 `aiobungie.error.NotFound` 196 The user was not found. 197 """ 198 payload = await self.rest.fetch_bungie_user(id) 199 200 return self.factory.deserialize_bungie_user(payload) 201 202 async def search_users( 203 self, name: str, / 204 ) -> iterators.Iterator[user.SearchableDestinyUser]: 205 """Search for players and return all players that matches the same name. 206 207 Parameters 208 ---------- 209 name : `buildins.str` 210 The user name. 211 212 Returns 213 ------- 214 `aiobungie.iterators.Iterator[aiobungie.crates.DestinyMembership]` 215 A sequence of destiny memberships. 216 """ 217 payload = await self.rest.search_users(name) 218 219 return iterators.Iterator( 220 [ 221 self.factory.deserialize_searched_user(user) 222 for user in payload["searchResults"] 223 ] 224 ) 225 226 async def fetch_user_themes(self) -> collections.Sequence[user.UserThemes]: 227 """Fetch all available user themes. 228 229 Returns 230 ------- 231 `collections.Sequence[aiobungie.crates.user.UserThemes]` 232 A sequence of user themes. 233 """ 234 data = await self.rest.fetch_user_themes() 235 236 return self.factory.deserialize_user_themes(data) 237 238 async def fetch_hard_types( 239 self, 240 credential: int, 241 type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID, 242 /, 243 ) -> user.HardLinkedMembership: 244 """Gets any hard linked membership given a credential. 245 Only works for credentials that are public just `aiobungie.CredentialType.STEAMID` right now. 246 Cross Save aware. 247 248 Parameters 249 ---------- 250 credential: `int` 251 A valid SteamID64 252 type: `aiobungie.CredentialType` 253 The credential type. This must not be changed 254 Since its only credential that works "currently" 255 256 Returns 257 ------- 258 `aiobungie.crates.user.HardLinkedMembership` 259 Information about the hard linked data. 260 """ 261 262 payload = await self.rest.fetch_hardlinked_credentials(credential, type) 263 264 return user.HardLinkedMembership( 265 id=int(payload["membershipId"]), 266 type=enums.MembershipType(payload["membershipType"]), 267 cross_save_type=enums.MembershipType(payload["CrossSaveOverriddenType"]), 268 ) 269 270 async def fetch_membership_from_id( 271 self, 272 id: int, 273 /, 274 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 275 ) -> user.User: 276 """Fetch Bungie user's memberships from their id. 277 278 Notes 279 ----- 280 * This returns both BungieNet membership and a sequence of the player's DestinyMemberships 281 Which includes Stadia, Xbox, Steam and PSN memberships if the player has them, 282 see `aiobungie.crates.user.DestinyMembership` for more details. 283 * If you only want the bungie user. Consider using `Client.fetch_user` method. 284 285 Parameters 286 ---------- 287 id : `int` 288 The user's id. 289 type : `aiobungie.MembershipType` 290 The user's membership type. 291 292 Returns 293 ------- 294 `aiobungie.crates.User` 295 A Bungie user with their membership types. 296 297 Raises 298 ------ 299 aiobungie.NotFound 300 The requested user was not found. 301 """ 302 payload = await self.rest.fetch_membership_from_id(id, type) 303 304 return self.factory.deserialize_user(payload) 305 306 async def fetch_user_credentials( 307 self, access_token: str, membership_id: int, / 308 ) -> collections.Sequence[user.UserCredentials]: 309 """Fetch an array of credential types attached to the requested account. 310 311 .. note:: 312 This method require OAuth2 Bearer access token. 313 314 Parameters 315 ---------- 316 access_token : `str` 317 The bearer access token associated with the bungie account. 318 membership_id : `int` 319 The id of the membership to return. 320 321 Returns 322 ------- 323 `collections.Sequence[aiobungie.crates.UserCredentials]` 324 A sequence of the attached user credentials. 325 326 Raises 327 ------ 328 `aiobungie.Unauthorized` 329 The access token was wrong or no access token passed. 330 """ 331 resp = await self.rest.fetch_user_credentials(access_token, membership_id) 332 333 return self.factory.deserialize_user_credentials(resp) 334 335 # * Destiny 2. 336 337 async def fetch_profile( 338 self, 339 member_id: int, 340 type: typedefs.IntAnd[enums.MembershipType], 341 components: list[enums.ComponentType], 342 auth: typing.Optional[str] = None, 343 ) -> components.Component: 344 """ 345 Fetch a bungie profile passing components to the request. 346 347 Parameters 348 ---------- 349 member_id: `int` 350 The member's id. 351 type: `aiobungie.MembershipType` 352 A valid membership type. 353 components : `list[aiobungie.ComponentType]` 354 List of profile components to collect and return. 355 356 Other Parameters 357 ---------------- 358 auth : `typing.Optional[str]` 359 A Bearer access_token to make the request with. 360 This is optional and limited to components that only requires an Authorization token. 361 362 Returns 363 -------- 364 `aiobungie.crates.Component` 365 A Destiny 2 player profile with its components. 366 Only passed components will be available if they exists. Otherwise they will be `None` 367 368 Raises 369 ------ 370 `aiobungie.MembershipTypeError` 371 The provided membership type was invalid. 372 """ 373 data = await self.rest.fetch_profile(member_id, type, components, auth) 374 return self.factory.deserialize_components(data) 375 376 async def fetch_linked_profiles( 377 self, 378 member_id: int, 379 member_type: typedefs.IntAnd[enums.MembershipType], 380 /, 381 *, 382 all: bool = False, 383 ) -> profile.LinkedProfile: 384 """Returns a summary information about all profiles linked to the requested member. 385 386 The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships. 387 388 .. note:: 389 It will only return linked accounts whose linkages you are allowed to view. 390 391 Parameters 392 ---------- 393 member_id : `int` 394 The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID. 395 member_type : `aiobungie.MembershipType` 396 The type for the membership whose linked Destiny account you want to return. 397 398 Other Parameters 399 ---------------- 400 all : `bool` 401 If provided and set to `True`, All memberships regardless 402 of whether they're obscured by overrides will be returned, 403 404 If provided and set to `False`, Only available memberships will be returned. 405 The default for this is `False`. 406 407 Returns 408 ------- 409 `aiobungie.crates.profile.LinkedProfile` 410 A linked profile object. 411 """ 412 resp = await self.rest.fetch_linked_profiles(member_id, member_type, all=all) 413 414 return self.factory.deserialize_linked_profiles(resp) 415 416 async def fetch_player( 417 self, 418 name: str, 419 code: int, 420 /, 421 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL, 422 ) -> collections.Sequence[user.DestinyMembership]: 423 """Fetch a Destiny 2 player's memberships. 424 425 Parameters 426 ----------- 427 name: `str` 428 The unique Bungie player name. 429 code : `int` 430 The unique Bungie display name code. 431 type: `aiobungie.internal.enums.MembershipType` 432 The player's membership type, e,g. XBOX, STEAM, PSN 433 434 Returns 435 -------- 436 `collections.Sequence[aiobungie.crates.DestinyMembership]` 437 A sequence of the found Destiny 2 player memberships. 438 An empty sequence will be returned if no one found. 439 440 Raises 441 ------ 442 `aiobungie.MembershipTypeError` 443 The provided membership type was invalid. 444 """ 445 resp = await self.rest.fetch_player(name, code, type) 446 447 return self.factory.deserialize_destiny_memberships(resp) 448 449 async def fetch_character( 450 self, 451 member_id: int, 452 membership_type: typedefs.IntAnd[enums.MembershipType], 453 character_id: int, 454 components: list[enums.ComponentType], 455 auth: typing.Optional[str] = None, 456 ) -> components.CharacterComponent: 457 """Fetch a Destiny 2 character. 458 459 Parameters 460 ---------- 461 member_id: `int` 462 A valid bungie member id. 463 character_id: `int` 464 The Destiny character id to retrieve. 465 membership_type: `aiobungie.internal.enums.MembershipType` 466 The member's membership type. 467 components: `list[aiobungie.ComponentType]` 468 Multiple arguments of character components to collect and return. 469 470 Other Parameters 471 ---------------- 472 auth : `typing.Optional[str]` 473 A Bearer access_token to make the request with. 474 This is optional and limited to components that only requires an Authorization token. 475 476 Returns 477 ------- 478 `aiobungie.crates.CharacterComponent` 479 A Bungie character component. 480 481 `aiobungie.MembershipTypeError` 482 The provided membership type was invalid. 483 """ 484 resp = await self.rest.fetch_character( 485 member_id, membership_type, character_id, components, auth 486 ) 487 488 return self.factory.deserialize_character_component(resp) 489 490 async def fetch_unique_weapon_history( 491 self, 492 membership_id: int, 493 character_id: int, 494 membership_type: typedefs.IntAnd[enums.MembershipType], 495 ) -> collections.Sequence[activity.ExtendedWeaponValues]: 496 """Fetch details about unique weapon usage for a character. Includes all exotics. 497 498 Parameters 499 ---------- 500 membership_id : `int` 501 The Destiny user membership id. 502 character_id : `int` 503 The character id to retrieve. 504 membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]` 505 The Destiny user's membership type. 506 507 Returns 508 ------- 509 `collections.Sequence[aiobungie.crates.ExtendedWeaponValues]` 510 A sequence of the weapon's extended values. 511 """ 512 resp = await self._rest.fetch_unique_weapon_history( 513 membership_id, character_id, membership_type 514 ) 515 516 return [ 517 self._factory.deserialize_extended_weapon_values(weapon) 518 for weapon in resp["weapons"] 519 ] 520 521 # * Destiny 2 Activities. 522 523 async def fetch_activities( 524 self, 525 member_id: int, 526 character_id: int, 527 mode: typedefs.IntAnd[enums.GameMode], 528 *, 529 membership_type: typedefs.IntAnd[ 530 enums.MembershipType 531 ] = enums.MembershipType.ALL, 532 page: int = 0, 533 limit: int = 250, 534 ) -> iterators.Iterator[activity.Activity]: 535 """Fetch a Destiny 2 activity for the specified character id. 536 537 Parameters 538 ---------- 539 member_id: `int` 540 The user id that starts with `4611`. 541 character_id: `int` 542 The id of the character to retrieve the activities for. 543 mode: `aiobungie.typedefs.IntAnd[aiobungie.internal.enums.GameMode]` 544 This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc. 545 546 Other Parameters 547 ---------------- 548 membership_type: `aiobungie.internal.enums.MembershipType` 549 The Member ship type, if nothing was passed than it will return all. 550 page: int 551 The page number. Default is `0` 552 limit: int 553 Limit the returned result. Default is `250`. 554 555 Returns 556 ------- 557 `aiobungie.iterators.Iterator[aiobungie.crates.Activity]` 558 An iterator of the player's activities. 559 560 Raises 561 ------ 562 `aiobungie.MembershipTypeError` 563 The provided membership type was invalid. 564 """ 565 resp = await self.rest.fetch_activities( 566 member_id, 567 character_id, 568 mode, 569 membership_type=membership_type, 570 page=page, 571 limit=limit, 572 ) 573 574 return self.factory.deserialize_activities(resp) 575 576 async def fetch_post_activity(self, instance_id: int, /) -> activity.PostActivity: 577 """Fetch a post activity details. 578 579 Parameters 580 ---------- 581 instance_id: `int` 582 The activity instance id. 583 584 Returns 585 ------- 586 `aiobungie.crates.PostActivity` 587 A post activity object. 588 """ 589 resp = await self.rest.fetch_post_activity(instance_id) 590 591 return self.factory.deserialize_post_activity(resp) 592 593 async def fetch_aggregated_activity_stats( 594 self, 595 character_id: int, 596 membership_id: int, 597 membership_type: typedefs.IntAnd[enums.MembershipType], 598 ) -> iterators.Iterator[activity.AggregatedActivity]: 599 """Fetch aggregated activity stats for a character. 600 601 Parameters 602 ---------- 603 character_id: `int` 604 The id of the character to retrieve the activities for. 605 membership_id: `int` 606 The id of the user that started with `4611`. 607 membership_type: `aiobungie.internal.enums.MembershipType` 608 The Member ship type. 609 610 Returns 611 ------- 612 `aiobungie.iterators.Iterator[aiobungie.crates.AggregatedActivity]` 613 An iterator of the player's activities. 614 615 Raises 616 ------ 617 `aiobungie.MembershipTypeError` 618 The provided membership type was invalid. 619 """ 620 resp = await self.rest.fetch_aggregated_activity_stats( 621 character_id, membership_id, membership_type 622 ) 623 624 return self.factory.deserialize_aggregated_activities(resp) 625 626 # * Destiny 2 Clans or GroupsV2. 627 628 async def fetch_clan_from_id( 629 self, 630 id: int, 631 /, 632 access_token: typing.Optional[str] = None, 633 ) -> clans.Clan: 634 """Fetch a Bungie Clan by its id. 635 636 Parameters 637 ----------- 638 id: `int` 639 The clan id. 640 641 Returns 642 -------- 643 `aiobungie.crates.Clan` 644 An Bungie clan. 645 646 Raises 647 ------ 648 `aiobungie.NotFound` 649 The clan was not found. 650 """ 651 resp = await self.rest.fetch_clan_from_id(id, access_token) 652 653 return self.factory.deserialize_clan(resp) 654 655 async def fetch_clan( 656 self, 657 name: str, 658 /, 659 access_token: typing.Optional[str] = None, 660 *, 661 type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 662 ) -> clans.Clan: 663 """Fetch a Clan by its name. 664 This method will return the first clan found with given name. 665 666 Parameters 667 ---------- 668 name: `str` 669 The clan name 670 671 Other Parameters 672 ---------------- 673 access_token : `typing.Optional[str]` 674 An optional access token to make the request with. 675 676 If the token was bound to a member of the clan, 677 This field `aiobungie.crates.Clan.current_user_membership` will be available 678 and will return the membership of the user who made this request. 679 type : `aiobungie.GroupType` 680 The group type, Default is aiobungie.GroupType.CLAN. 681 682 Returns 683 ------- 684 `aiobungie.crates.Clan` 685 A Bungie clan. 686 687 Raises 688 ------ 689 `aiobungie.NotFound` 690 The clan was not found. 691 """ 692 resp = await self.rest.fetch_clan(name, access_token, type=type) 693 694 return self.factory.deserialize_clan(resp) 695 696 async def fetch_clan_conversations( 697 self, clan_id: int, / 698 ) -> collections.Sequence[clans.ClanConversation]: 699 """Fetch the conversations/chat channels of the given clan id. 700 701 Parameters 702 ---------- 703 clan_id : `int` 704 The clan id. 705 706 Returns 707 `collections.Sequence[aiobungie.crates.ClanConversation]` 708 A sequence of the clan chat channels. 709 """ 710 resp = await self.rest.fetch_clan_conversations(clan_id) 711 712 return self.factory.deserialize_clan_conversations(resp) 713 714 async def fetch_clan_admins( 715 self, clan_id: int, / 716 ) -> iterators.Iterator[clans.ClanMember]: 717 """Fetch the clan founder and admins. 718 719 Parameters 720 ---------- 721 clan_id : `int` 722 The clan id. 723 724 Returns 725 ------- 726 `aiobungie.iterators.Iterator[aiobungie.crates.ClanMember]` 727 An iterator over the found clan admins and founder. 728 729 Raises 730 ------ 731 `aiobungie.NotFound` 732 The requested clan was not found. 733 """ 734 resp = await self.rest.fetch_clan_admins(clan_id) 735 736 return self.factory.deserialize_clan_members(resp) 737 738 async def fetch_groups_for_member( 739 self, 740 member_id: int, 741 member_type: typedefs.IntAnd[enums.MembershipType], 742 /, 743 *, 744 filter: int = 0, 745 group_type: enums.GroupType = enums.GroupType.CLAN, 746 ) -> collections.Sequence[clans.GroupMember]: 747 """Fetch information about the groups that a given member has joined. 748 749 Parameters 750 ---------- 751 member_id : `int` 752 The member's id 753 member_type : `aiobungie.MembershipType` 754 The member's membership type. 755 756 Other Parameters 757 ---------------- 758 filter : `int` 759 Filter apply to list of joined groups. This Default to `0` 760 group_type : `aiobungie.GroupType` 761 The group's type. 762 This is always set to `aiobungie.GroupType.CLAN` and should not be changed. 763 764 Returns 765 ------- 766 `collections.Sequence[aiobungie.crates.GroupMember]` 767 A sequence of joined groups for the fetched member. 768 """ 769 resp = await self.rest.fetch_groups_for_member( 770 member_id, member_type, filter=filter, group_type=group_type 771 ) 772 773 return [ 774 self.factory.deserialize_group_member(group) for group in resp["results"] 775 ] 776 777 async def fetch_potential_groups_for_member( 778 self, 779 member_id: int, 780 member_type: typedefs.IntAnd[enums.MembershipType], 781 /, 782 *, 783 filter: int = 0, 784 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 785 ) -> collections.Sequence[clans.GroupMember]: 786 """Fetch the potential groups for a clan member. 787 788 Parameters 789 ---------- 790 member_id : `int` 791 The member's id 792 member_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]` 793 The member's membership type. 794 795 Other Parameters 796 ---------------- 797 filter : `int` 798 Filter apply to list of joined groups. This Default to `0` 799 group_type : `aiobungie.typedefs.IntAnd[aiobungie.GroupType]` 800 The group's type. 801 This is always set to `aiobungie.GroupType.CLAN` and should not be changed. 802 803 Returns 804 ------- 805 `collections.Sequence[aiobungie.crates.GroupMember]` 806 A sequence of joined potential groups for the fetched member. 807 """ 808 resp = await self.rest.fetch_potential_groups_for_member( 809 member_id, member_type, filter=filter, group_type=group_type 810 ) 811 812 return [ 813 self.factory.deserialize_group_member(group) for group in resp["results"] 814 ] 815 816 async def fetch_clan_members( 817 self, 818 clan_id: int, 819 /, 820 *, 821 name: typing.Optional[str] = None, 822 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 823 ) -> iterators.Iterator[clans.ClanMember]: 824 """Fetch Bungie clan members. 825 826 Parameters 827 ---------- 828 clan_id : `int` 829 The clans id 830 831 Other Parameters 832 ---------------- 833 name : `typing.Optional[str]` 834 If provided, Only players matching this name will be returned. 835 type : `aiobungie.MembershipType` 836 An optional clan member's membership type. 837 This parameter is used to filter the returned results 838 by the provided membership, For an example XBox memberships only, 839 Otherwise will return all memberships. 840 841 Returns 842 ------- 843 `aiobungie.iterators.Iterator[aiobungie.crates.ClanMember]` 844 An iterator over the bungie clan members. 845 846 Raises 847 ------ 848 `aiobungie.NotFound` 849 The clan was not found. 850 """ 851 resp = await self.rest.fetch_clan_members(clan_id, type=type, name=name) 852 853 return self.factory.deserialize_clan_members(resp) 854 855 async def fetch_clan_banners(self) -> collections.Sequence[clans.ClanBanner]: 856 """Fetch the clan banners. 857 858 Returns 859 ------- 860 `collections.Sequence[aiobungie.crates.ClanBanner]` 861 A sequence of the clan banners. 862 """ 863 resp = await self.rest.fetch_clan_banners() 864 865 return self.factory.deserialize_clan_banners(resp) 866 867 # This method is required to be here since it deserialize the clan. 868 async def kick_clan_member( 869 self, 870 access_token: str, 871 /, 872 group_id: int, 873 membership_id: int, 874 membership_type: typedefs.IntAnd[enums.MembershipType], 875 ) -> clans.Clan: 876 """Kick a member from the clan. 877 878 .. note:: 879 This request requires OAuth2: oauth2: `AdminGroups` scope. 880 881 Parameters 882 ---------- 883 access_token : `str` 884 The bearer access token associated with the bungie account. 885 group_id: `int` 886 The group id. 887 membership_id : `int` 888 The member id to kick. 889 membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]` 890 The member's membership type. 891 892 Returns 893 ------- 894 `aiobungie.crates.clan.Clan` 895 The clan that the member was kicked from. 896 """ 897 resp = await self.rest.kick_clan_member( 898 access_token, 899 group_id=group_id, 900 membership_id=membership_id, 901 membership_type=membership_type, 902 ) 903 904 return self.factory.deserialize_clan(resp) 905 906 async def fetch_clan_weekly_rewards(self, clan_id: int) -> milestones.Milestone: 907 """Fetch a Bungie clan's weekly reward state. 908 909 Parameters 910 ---------- 911 clan_id : `int` 912 The clan's id. 913 914 Returns 915 ------- 916 `aiobungie.crates.Milestone` 917 A runtime status of the clan's milestone data. 918 """ 919 920 resp = await self.rest.fetch_clan_weekly_rewards(clan_id) 921 922 return self.factory.deserialize_milestone(resp) 923 924 # * Destiny 2 Entities aka Definitions. 925 926 async def fetch_inventory_item(self, hash: int, /) -> entity.InventoryEntity: 927 """Fetch a static inventory item entity given a its hash. 928 929 Parameters 930 ---------- 931 hash: `int` 932 Inventory item's hash. 933 934 Returns 935 ------- 936 `aiobungie.crates.InventoryEntity` 937 A bungie inventory item. 938 """ 939 resp = await self.rest.fetch_inventory_item(hash) 940 941 return self.factory.deserialize_inventory_entity(resp) 942 943 async def fetch_objective_entity(self, hash: int, /) -> entity.ObjectiveEntity: 944 """Fetch a Destiny objective entity given a its hash. 945 946 Parameters 947 ---------- 948 hash: `int` 949 objective's hash. 950 951 Returns 952 ------- 953 `aiobungie.crates.ObjectiveEntity` 954 An objective entity item. 955 """ 956 resp = await self.rest.fetch_objective_entity(hash) 957 958 return self.factory.deserialize_objective_entity(resp) 959 960 async def search_entities( 961 self, name: str, entity_type: str, *, page: int = 0 962 ) -> iterators.Iterator[entity.SearchableEntity]: 963 """Search for Destiny2 entities given a name and its type. 964 965 Parameters 966 ---------- 967 name : `str` 968 The name of the entity, i.e., Thunderlord, One thousand voices. 969 entity_type : `str` 970 The type of the entity, AKA Definition, 971 For an example `DestinyInventoryItemDefinition` for emblems, weapons, and other inventory items. 972 973 Other Parameters 974 ---------------- 975 page : `int` 976 An optional page to return. Default to 0. 977 978 Returns 979 ------- 980 `aiobungie.iterators.Iterator[aiobungie.crates.SearchableEntity]` 981 An iterator over the found results matching the provided name. 982 """ 983 resp = await self.rest.search_entities(name, entity_type, page=page) 984 985 return self.factory.deserialize_inventory_results(resp) 986 987 # Fireteams 988 989 async def fetch_fireteams( 990 self, 991 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 992 *, 993 platform: typedefs.IntAnd[ 994 fireteams.FireteamPlatform 995 ] = fireteams.FireteamPlatform.ANY, 996 language: typing.Union[ 997 fireteams.FireteamLanguage, str 998 ] = fireteams.FireteamLanguage.ALL, 999 date_range: int = 0, 1000 page: int = 0, 1001 slots_filter: int = 0, 1002 ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]: 1003 """Fetch public Bungie fireteams with open slots. 1004 1005 Parameters 1006 ---------- 1007 activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]` 1008 The fireteam activity type. 1009 1010 Other Parameters 1011 ---------------- 1012 platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]` 1013 If this is provided. Then the results will be filtered with the given platform. 1014 Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms. 1015 language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]` 1016 A locale language to filter the used language in that fireteam. 1017 Defaults to `aiobungie.crates.FireteamLanguage.ALL` 1018 date_range : `int` 1019 An integer to filter the date range of the returned fireteams. Defaults to `aiobungie.FireteamDate.ALL`. 1020 page : `int` 1021 The page number. By default its `0` which returns all available activities. 1022 slots_filter : `int` 1023 Filter the returned fireteams based on available slots. Default is `0` 1024 1025 Returns 1026 ------- 1027 `typing.Optional[collections.Sequence[fireteams.Fireteam]]` 1028 A sequence of `aiobungie.crates.Fireteam` or `None`. 1029 """ 1030 1031 resp = await self.rest.fetch_fireteams( 1032 activity_type, 1033 platform=platform, 1034 language=language, 1035 date_range=date_range, 1036 page=page, 1037 slots_filter=slots_filter, 1038 ) 1039 1040 return self.factory.deserialize_fireteams(resp) 1041 1042 async def fetch_available_clan_fireteams( 1043 self, 1044 access_token: str, 1045 group_id: int, 1046 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 1047 *, 1048 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1049 language: typing.Union[fireteams.FireteamLanguage, str], 1050 date_range: int = 0, 1051 page: int = 0, 1052 public_only: bool = False, 1053 slots_filter: int = 0, 1054 ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]: 1055 """Fetch a clan's fireteams with open slots. 1056 1057 .. note:: 1058 This method requires OAuth2: ReadGroups scope. 1059 1060 Parameters 1061 ---------- 1062 access_token : `str` 1063 The bearer access token associated with the bungie account. 1064 group_id : `int` 1065 The group/clan id of the fireteam. 1066 activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]` 1067 The fireteam activity type. 1068 1069 Other Parameters 1070 ---------------- 1071 platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]` 1072 If this is provided. Then the results will be filtered with the given platform. 1073 Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms. 1074 language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]` 1075 A locale language to filter the used language in that fireteam. 1076 Defaults to `aiobungie.crates.FireteamLanguage.ALL` 1077 date_range : `int` 1078 An integer to filter the date range of the returned fireteams. Defaults to `0`. 1079 page : `int` 1080 The page number. By default its `0` which returns all available activities. 1081 public_only: `bool` 1082 If set to True, Then only public fireteams will be returned. 1083 slots_filter : `int` 1084 Filter the returned fireteams based on available slots. Default is `0` 1085 1086 Returns 1087 ------- 1088 `typing.Optional[collections.Sequence[aiobungie.crates.Fireteam]]` 1089 A sequence of fireteams found in the clan. 1090 `None` will be returned if nothing was found. 1091 """ 1092 resp = await self.rest.fetch_available_clan_fireteams( 1093 access_token, 1094 group_id, 1095 activity_type, 1096 platform=platform, 1097 language=language, 1098 date_range=date_range, 1099 page=page, 1100 public_only=public_only, 1101 slots_filter=slots_filter, 1102 ) 1103 1104 return self.factory.deserialize_fireteams(resp) 1105 1106 async def fetch_clan_fireteam( 1107 self, access_token: str, fireteam_id: int, group_id: int 1108 ) -> fireteams.AvailableFireteam: 1109 """Fetch a specific clan fireteam. 1110 1111 .. note:: 1112 This method requires OAuth2: ReadGroups scope. 1113 1114 Parameters 1115 ---------- 1116 access_token : `str` 1117 The bearer access token associated with the bungie account. 1118 group_id : `int` 1119 The group/clan id to fetch the fireteam from. 1120 fireteam_id : `int` 1121 The fireteam id to fetch. 1122 1123 Returns 1124 ------- 1125 `typing.Optional[aiobungie.crates.AvailableFireteam]` 1126 A sequence of available fireteams objects if exists. else `None` will be returned. 1127 """ 1128 resp = await self.rest.fetch_clan_fireteam(access_token, fireteam_id, group_id) 1129 1130 return self.factory.deserialize_available_fireteams(resp, no_results=True) # type: ignore[return-value] 1131 1132 async def fetch_my_clan_fireteams( 1133 self, 1134 access_token: str, 1135 group_id: int, 1136 *, 1137 include_closed: bool = True, 1138 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1139 language: typing.Union[fireteams.FireteamLanguage, str], 1140 filtered: bool = True, 1141 page: int = 0, 1142 ) -> collections.Sequence[fireteams.AvailableFireteam]: 1143 """A method that's similar to `fetch_fireteams` but requires OAuth2. 1144 1145 .. note:: 1146 This method requires OAuth2: ReadGroups scope. 1147 1148 Parameters 1149 ---------- 1150 access_token : str 1151 The bearer access token associated with the bungie account. 1152 group_id : int 1153 The group/clan id to fetch. 1154 1155 Other Parameters 1156 ---------------- 1157 include_closed : bool 1158 If provided and set to True, It will also return closed fireteams. 1159 If provided and set to False, It will only return public fireteams. Default is True. 1160 platform : aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform] 1161 If this is provided. Then the results will be filtered with the given platform. 1162 Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms. 1163 language : typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str] 1164 A locale language to filter the used language in that fireteam. 1165 Defaults to aiobungie.crates.FireteamLanguage.ALL 1166 filtered : bool 1167 If set to True, it will filter by clan. Otherwise not. Default is True. 1168 page : int 1169 The page number. By default its 0 which returns all available activities. 1170 1171 Returns 1172 ------- 1173 `collections.Sequence[aiobungie.crates.AvailableFireteam]` 1174 A sequence of available fireteams objects if exists. else `None` will be returned. 1175 """ 1176 resp = await self.rest.fetch_my_clan_fireteams( 1177 access_token, 1178 group_id, 1179 include_closed=include_closed, 1180 platform=platform, 1181 language=language, 1182 filtered=filtered, 1183 page=page, 1184 ) 1185 1186 return self.factory.deserialize_available_fireteams(resp) # type: ignore[return-value] 1187 1188 # Friends and social. 1189 1190 async def fetch_friends( 1191 self, access_token: str, / 1192 ) -> collections.Sequence[friends.Friend]: 1193 """Fetch bungie friend list. 1194 1195 .. note:: 1196 This requests OAuth2: ReadUserData scope. 1197 1198 Parameters 1199 ----------- 1200 access_token : `str` 1201 The bearer access token associated with the bungie account. 1202 1203 Returns 1204 ------- 1205 `collections.Sequence[aiobungie.crates.Friend]` 1206 A sequence of the friends associated with that access token. 1207 """ 1208 1209 resp = await self.rest.fetch_friends(access_token) 1210 1211 return self.factory.deserialize_friends(resp) 1212 1213 async def fetch_friend_requests( 1214 self, access_token: str, / 1215 ) -> friends.FriendRequestView: 1216 """Fetch pending bungie friend requests queue. 1217 1218 .. note:: 1219 This requests OAuth2: ReadUserData scope. 1220 1221 Parameters 1222 ----------- 1223 access_token : `str` 1224 The bearer access token associated with the bungie account. 1225 1226 Returns 1227 ------- 1228 `aiobungie.crates.FriendRequestView` 1229 A friend requests view of that associated access token. 1230 """ 1231 1232 resp = await self.rest.fetch_friend_requests(access_token) 1233 1234 return self.factory.deserialize_friend_requests(resp) 1235 1236 # Applications and Developer portal. 1237 1238 async def fetch_application(self, appid: int, /) -> application.Application: 1239 """Fetch a Bungie application. 1240 1241 Parameters 1242 ----------- 1243 appid: `int` 1244 The application id. 1245 1246 Returns 1247 -------- 1248 `aiobungie.crates.Application` 1249 A Bungie application. 1250 """ 1251 resp = await self.rest.fetch_application(appid) 1252 1253 return self.factory.deserialize_app(resp) 1254 1255 # Milestones 1256 1257 async def fetch_public_milestone_content( 1258 self, milestone_hash: int, / 1259 ) -> milestones.MilestoneContent: 1260 """Fetch the milestone content given its hash. 1261 1262 Parameters 1263 ---------- 1264 milestone_hash : `int` 1265 The milestone hash. 1266 1267 Returns 1268 ------- 1269 `aiobungie.crates.milestones.MilestoneContent` 1270 A milestone content object. 1271 """ 1272 resp = await self.rest.fetch_public_milestone_content(milestone_hash) 1273 1274 return self.factory.deserialize_public_milestone_content(resp)
Standard Bungie API client application.
This client deserialize the REST JSON responses using Factory
and returns aiobungie.crates Python object implementations of the responses.
A aiobungie.RESTClient REST client can also be used alone for low-level concepts.
Example
import aiobungie
client = aiobungie.Client('...')
async def main():
async with client.rest:
user = await client.fetch_current_user_memberships('...')
print(user)
Parameters
- token (
str): Your Bungie's API key or Token from the developer's portal.
Other Parameters
- max_retries (
int): The max retries number to retry if the request hit a5xxstatus code. - client_secret (
str | None): An optional application client secret, This is only needed if you're fetching OAuth2 tokens with this client. - client_id (
int | None): An optional application client id, This is only needed if you're fetching OAuth2 tokens with this client.
100 def __init__( 101 self, 102 token: str, 103 /, 104 *, 105 client_secret: typing.Optional[str] = None, 106 client_id: typing.Optional[int] = None, 107 dumps: typedefs.Dumps = helpers.dumps, 108 loads: typedefs.Loads = helpers.loads, 109 max_retries: int = 4, 110 ) -> None: 111 self._rest = rest_.RESTClient( 112 token, 113 dumps=dumps, 114 loads=loads, 115 client_secret=client_secret, 116 client_id=client_id, 117 max_retries=max_retries, 118 ) 119 120 self._factory = factory_.Factory(self)
A mutable mapping storage for the user's needs.
138 def run( 139 self, future: collections.Coroutine[typing.Any, None, None], debug: bool = False 140 ) -> None: 141 loop: typing.Final[asyncio.AbstractEventLoop] = helpers.get_or_make_loop() 142 try: 143 if not loop.is_running(): 144 loop.set_debug(debug) 145 loop.run_until_complete(future) 146 147 except Exception as exc: 148 raise RuntimeError(f"Failed to run {future.__qualname__}") from exc 149 150 except KeyboardInterrupt: 151 _LOG.warn("Unexpected Keyboard interrupt. Exiting.") 152 return
Runs a coroutine function until its complete.
This is equivalent to asyncio.get_event_loop().run_until_complete(...)
Parameters
- future (
collections.Coroutine[None, None, None]): A coroutine object. - debug (
bool): Either to enable asyncio debug or not. Disabled by default.
Example
async def main() -> None:
await fetch(...)
# Run the coroutine.
client.run(main())
156 async def fetch_current_user_memberships(self, access_token: str, /) -> user.User: 157 """Fetch and return a user object of the bungie net user associated with account. 158 159 .. warning:: 160 This method requires OAuth2 scope and a Bearer access token. 161 162 Parameters 163 ---------- 164 access_token : `str` 165 A valid Bearer access token for the authorization. 166 167 Returns 168 ------- 169 `aiobungie.crates.user.User` 170 A user object includes the Destiny memberships and Bungie.net user. 171 """ 172 resp = await self.rest.fetch_current_user_memberships(access_token) 173 174 return self.factory.deserialize_user(resp)
Fetch and return a user object of the bungie net user associated with account.
This method requires OAuth2 scope and a Bearer access token.
Parameters
- access_token (
str): A valid Bearer access token for the authorization.
Returns
aiobungie.crates.user.User: A user object includes the Destiny memberships and Bungie.net user.
176 async def fetch_bungie_user(self, id: int, /) -> user.BungieUser: 177 """Fetch a Bungie user by their BungieNet id. 178 179 .. note:: 180 This returns a Bungie user membership only. Take a look at `Client.fetch_membership_from_id` 181 for other memberships. 182 183 Parameters 184 ---------- 185 id: `int` 186 The user id. 187 188 Returns 189 ------- 190 `aiobungie.crates.user.BungieUser` 191 A Bungie user. 192 193 Raises 194 ------ 195 `aiobungie.error.NotFound` 196 The user was not found. 197 """ 198 payload = await self.rest.fetch_bungie_user(id) 199 200 return self.factory.deserialize_bungie_user(payload)
Fetch a Bungie user by their BungieNet id.
This returns a Bungie user membership only. Take a look at Client.fetch_membership_from_id
for other memberships.
Parameters
- id (
int): The user id.
Returns
aiobungie.crates.user.BungieUser: A Bungie user.
Raises
NotFound: The user was not found.
202 async def search_users( 203 self, name: str, / 204 ) -> iterators.Iterator[user.SearchableDestinyUser]: 205 """Search for players and return all players that matches the same name. 206 207 Parameters 208 ---------- 209 name : `buildins.str` 210 The user name. 211 212 Returns 213 ------- 214 `aiobungie.iterators.Iterator[aiobungie.crates.DestinyMembership]` 215 A sequence of destiny memberships. 216 """ 217 payload = await self.rest.search_users(name) 218 219 return iterators.Iterator( 220 [ 221 self.factory.deserialize_searched_user(user) 222 for user in payload["searchResults"] 223 ] 224 )
Search for players and return all players that matches the same name.
Parameters
- name (
buildins.str): The user name.
Returns
aiobungie.iterators.Iterator[aiobungie.crates.DestinyMembership]: A sequence of destiny memberships.
226 async def fetch_user_themes(self) -> collections.Sequence[user.UserThemes]: 227 """Fetch all available user themes. 228 229 Returns 230 ------- 231 `collections.Sequence[aiobungie.crates.user.UserThemes]` 232 A sequence of user themes. 233 """ 234 data = await self.rest.fetch_user_themes() 235 236 return self.factory.deserialize_user_themes(data)
Fetch all available user themes.
Returns
collections.Sequence[aiobungie.crates.user.UserThemes]: A sequence of user themes.
238 async def fetch_hard_types( 239 self, 240 credential: int, 241 type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID, 242 /, 243 ) -> user.HardLinkedMembership: 244 """Gets any hard linked membership given a credential. 245 Only works for credentials that are public just `aiobungie.CredentialType.STEAMID` right now. 246 Cross Save aware. 247 248 Parameters 249 ---------- 250 credential: `int` 251 A valid SteamID64 252 type: `aiobungie.CredentialType` 253 The credential type. This must not be changed 254 Since its only credential that works "currently" 255 256 Returns 257 ------- 258 `aiobungie.crates.user.HardLinkedMembership` 259 Information about the hard linked data. 260 """ 261 262 payload = await self.rest.fetch_hardlinked_credentials(credential, type) 263 264 return user.HardLinkedMembership( 265 id=int(payload["membershipId"]), 266 type=enums.MembershipType(payload["membershipType"]), 267 cross_save_type=enums.MembershipType(payload["CrossSaveOverriddenType"]), 268 )
Gets any hard linked membership given a credential.
Only works for credentials that are public just aiobungie.CredentialType.STEAMID right now.
Cross Save aware.
Parameters
- credential (
int): A valid SteamID64 - type (
aiobungie.CredentialType): The credential type. This must not be changed Since its only credential that works "currently"
Returns
aiobungie.crates.user.HardLinkedMembership: Information about the hard linked data.
270 async def fetch_membership_from_id( 271 self, 272 id: int, 273 /, 274 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 275 ) -> user.User: 276 """Fetch Bungie user's memberships from their id. 277 278 Notes 279 ----- 280 * This returns both BungieNet membership and a sequence of the player's DestinyMemberships 281 Which includes Stadia, Xbox, Steam and PSN memberships if the player has them, 282 see `aiobungie.crates.user.DestinyMembership` for more details. 283 * If you only want the bungie user. Consider using `Client.fetch_user` method. 284 285 Parameters 286 ---------- 287 id : `int` 288 The user's id. 289 type : `aiobungie.MembershipType` 290 The user's membership type. 291 292 Returns 293 ------- 294 `aiobungie.crates.User` 295 A Bungie user with their membership types. 296 297 Raises 298 ------ 299 aiobungie.NotFound 300 The requested user was not found. 301 """ 302 payload = await self.rest.fetch_membership_from_id(id, type) 303 304 return self.factory.deserialize_user(payload)
Fetch Bungie user's memberships from their id.
Notes
- This returns both BungieNet membership and a sequence of the player's DestinyMemberships
Which includes Stadia, Xbox, Steam and PSN memberships if the player has them,
see
aiobungie.crates.user.DestinyMembershipfor more details. - If you only want the bungie user. Consider using
Client.fetch_usermethod.
Parameters
- id (
int): The user's id. - type (
aiobungie.MembershipType): The user's membership type.
Returns
aiobungie.crates.User: A Bungie user with their membership types.
Raises
- aiobungie.NotFound: The requested user was not found.
306 async def fetch_user_credentials( 307 self, access_token: str, membership_id: int, / 308 ) -> collections.Sequence[user.UserCredentials]: 309 """Fetch an array of credential types attached to the requested account. 310 311 .. note:: 312 This method require OAuth2 Bearer access token. 313 314 Parameters 315 ---------- 316 access_token : `str` 317 The bearer access token associated with the bungie account. 318 membership_id : `int` 319 The id of the membership to return. 320 321 Returns 322 ------- 323 `collections.Sequence[aiobungie.crates.UserCredentials]` 324 A sequence of the attached user credentials. 325 326 Raises 327 ------ 328 `aiobungie.Unauthorized` 329 The access token was wrong or no access token passed. 330 """ 331 resp = await self.rest.fetch_user_credentials(access_token, membership_id) 332 333 return self.factory.deserialize_user_credentials(resp)
Fetch an array of credential types attached to the requested account.
This method require OAuth2 Bearer access token.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - membership_id (
int): The id of the membership to return.
Returns
collections.Sequence[aiobungie.crates.UserCredentials]: A sequence of the attached user credentials.
Raises
aiobungie.Unauthorized: The access token was wrong or no access token passed.
337 async def fetch_profile( 338 self, 339 member_id: int, 340 type: typedefs.IntAnd[enums.MembershipType], 341 components: list[enums.ComponentType], 342 auth: typing.Optional[str] = None, 343 ) -> components.Component: 344 """ 345 Fetch a bungie profile passing components to the request. 346 347 Parameters 348 ---------- 349 member_id: `int` 350 The member's id. 351 type: `aiobungie.MembershipType` 352 A valid membership type. 353 components : `list[aiobungie.ComponentType]` 354 List of profile components to collect and return. 355 356 Other Parameters 357 ---------------- 358 auth : `typing.Optional[str]` 359 A Bearer access_token to make the request with. 360 This is optional and limited to components that only requires an Authorization token. 361 362 Returns 363 -------- 364 `aiobungie.crates.Component` 365 A Destiny 2 player profile with its components. 366 Only passed components will be available if they exists. Otherwise they will be `None` 367 368 Raises 369 ------ 370 `aiobungie.MembershipTypeError` 371 The provided membership type was invalid. 372 """ 373 data = await self.rest.fetch_profile(member_id, type, components, auth) 374 return self.factory.deserialize_components(data)
Fetch a bungie profile passing components to the request.
Parameters
- member_id (
int): The member's id. - type (
aiobungie.MembershipType): A valid membership type. - components (
list[aiobungie.ComponentType]): List of profile components to collect and return.
Other Parameters
- auth (
typing.Optional[str]): A Bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
aiobungie.crates.Component: A Destiny 2 player profile with its components. Only passed components will be available if they exists. Otherwise they will beNone
Raises
aiobungie.MembershipTypeError: The provided membership type was invalid.
376 async def fetch_linked_profiles( 377 self, 378 member_id: int, 379 member_type: typedefs.IntAnd[enums.MembershipType], 380 /, 381 *, 382 all: bool = False, 383 ) -> profile.LinkedProfile: 384 """Returns a summary information about all profiles linked to the requested member. 385 386 The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships. 387 388 .. note:: 389 It will only return linked accounts whose linkages you are allowed to view. 390 391 Parameters 392 ---------- 393 member_id : `int` 394 The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID. 395 member_type : `aiobungie.MembershipType` 396 The type for the membership whose linked Destiny account you want to return. 397 398 Other Parameters 399 ---------------- 400 all : `bool` 401 If provided and set to `True`, All memberships regardless 402 of whether they're obscured by overrides will be returned, 403 404 If provided and set to `False`, Only available memberships will be returned. 405 The default for this is `False`. 406 407 Returns 408 ------- 409 `aiobungie.crates.profile.LinkedProfile` 410 A linked profile object. 411 """ 412 resp = await self.rest.fetch_linked_profiles(member_id, member_type, all=all) 413 414 return self.factory.deserialize_linked_profiles(resp)
Returns a summary information about all profiles linked to the requested member.
The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships.
It will only return linked accounts whose linkages you are allowed to view.
Parameters
- member_id (
int): The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID. - member_type (
aiobungie.MembershipType): The type for the membership whose linked Destiny account you want to return.
Other Parameters
all (
bool): If provided and set toTrue, All memberships regardless of whether they're obscured by overrides will be returned,If provided and set to
False, Only available memberships will be returned. The default for this isFalse.
Returns
aiobungie.crates.profile.LinkedProfile: A linked profile object.
416 async def fetch_player( 417 self, 418 name: str, 419 code: int, 420 /, 421 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL, 422 ) -> collections.Sequence[user.DestinyMembership]: 423 """Fetch a Destiny 2 player's memberships. 424 425 Parameters 426 ----------- 427 name: `str` 428 The unique Bungie player name. 429 code : `int` 430 The unique Bungie display name code. 431 type: `aiobungie.internal.enums.MembershipType` 432 The player's membership type, e,g. XBOX, STEAM, PSN 433 434 Returns 435 -------- 436 `collections.Sequence[aiobungie.crates.DestinyMembership]` 437 A sequence of the found Destiny 2 player memberships. 438 An empty sequence will be returned if no one found. 439 440 Raises 441 ------ 442 `aiobungie.MembershipTypeError` 443 The provided membership type was invalid. 444 """ 445 resp = await self.rest.fetch_player(name, code, type) 446 447 return self.factory.deserialize_destiny_memberships(resp)
Fetch a Destiny 2 player's memberships.
Parameters
- name (
str): The unique Bungie player name. - code (
int): The unique Bungie display name code. - type (
MembershipType): The player's membership type, e,g. XBOX, STEAM, PSN
Returns
collections.Sequence[aiobungie.crates.DestinyMembership]: A sequence of the found Destiny 2 player memberships. An empty sequence will be returned if no one found.
Raises
aiobungie.MembershipTypeError: The provided membership type was invalid.
449 async def fetch_character( 450 self, 451 member_id: int, 452 membership_type: typedefs.IntAnd[enums.MembershipType], 453 character_id: int, 454 components: list[enums.ComponentType], 455 auth: typing.Optional[str] = None, 456 ) -> components.CharacterComponent: 457 """Fetch a Destiny 2 character. 458 459 Parameters 460 ---------- 461 member_id: `int` 462 A valid bungie member id. 463 character_id: `int` 464 The Destiny character id to retrieve. 465 membership_type: `aiobungie.internal.enums.MembershipType` 466 The member's membership type. 467 components: `list[aiobungie.ComponentType]` 468 Multiple arguments of character components to collect and return. 469 470 Other Parameters 471 ---------------- 472 auth : `typing.Optional[str]` 473 A Bearer access_token to make the request with. 474 This is optional and limited to components that only requires an Authorization token. 475 476 Returns 477 ------- 478 `aiobungie.crates.CharacterComponent` 479 A Bungie character component. 480 481 `aiobungie.MembershipTypeError` 482 The provided membership type was invalid. 483 """ 484 resp = await self.rest.fetch_character( 485 member_id, membership_type, character_id, components, auth 486 ) 487 488 return self.factory.deserialize_character_component(resp)
Fetch a Destiny 2 character.
Parameters
- member_id (
int): A valid bungie member id. - character_id (
int): The Destiny character id to retrieve. - membership_type (
MembershipType): The member's membership type. - components (
list[aiobungie.ComponentType]): Multiple arguments of character components to collect and return.
Other Parameters
- auth (
typing.Optional[str]): A Bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
aiobungie.crates.CharacterComponent: A Bungie character component.aiobungie.MembershipTypeError: The provided membership type was invalid.
490 async def fetch_unique_weapon_history( 491 self, 492 membership_id: int, 493 character_id: int, 494 membership_type: typedefs.IntAnd[enums.MembershipType], 495 ) -> collections.Sequence[activity.ExtendedWeaponValues]: 496 """Fetch details about unique weapon usage for a character. Includes all exotics. 497 498 Parameters 499 ---------- 500 membership_id : `int` 501 The Destiny user membership id. 502 character_id : `int` 503 The character id to retrieve. 504 membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]` 505 The Destiny user's membership type. 506 507 Returns 508 ------- 509 `collections.Sequence[aiobungie.crates.ExtendedWeaponValues]` 510 A sequence of the weapon's extended values. 511 """ 512 resp = await self._rest.fetch_unique_weapon_history( 513 membership_id, character_id, membership_type 514 ) 515 516 return [ 517 self._factory.deserialize_extended_weapon_values(weapon) 518 for weapon in resp["weapons"] 519 ]
Fetch details about unique weapon usage for a character. Includes all exotics.
Parameters
- membership_id (
int): The Destiny user membership id. - character_id (
int): The character id to retrieve. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny user's membership type.
Returns
collections.Sequence[aiobungie.crates.ExtendedWeaponValues]: A sequence of the weapon's extended values.
523 async def fetch_activities( 524 self, 525 member_id: int, 526 character_id: int, 527 mode: typedefs.IntAnd[enums.GameMode], 528 *, 529 membership_type: typedefs.IntAnd[ 530 enums.MembershipType 531 ] = enums.MembershipType.ALL, 532 page: int = 0, 533 limit: int = 250, 534 ) -> iterators.Iterator[activity.Activity]: 535 """Fetch a Destiny 2 activity for the specified character id. 536 537 Parameters 538 ---------- 539 member_id: `int` 540 The user id that starts with `4611`. 541 character_id: `int` 542 The id of the character to retrieve the activities for. 543 mode: `aiobungie.typedefs.IntAnd[aiobungie.internal.enums.GameMode]` 544 This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc. 545 546 Other Parameters 547 ---------------- 548 membership_type: `aiobungie.internal.enums.MembershipType` 549 The Member ship type, if nothing was passed than it will return all. 550 page: int 551 The page number. Default is `0` 552 limit: int 553 Limit the returned result. Default is `250`. 554 555 Returns 556 ------- 557 `aiobungie.iterators.Iterator[aiobungie.crates.Activity]` 558 An iterator of the player's activities. 559 560 Raises 561 ------ 562 `aiobungie.MembershipTypeError` 563 The provided membership type was invalid. 564 """ 565 resp = await self.rest.fetch_activities( 566 member_id, 567 character_id, 568 mode, 569 membership_type=membership_type, 570 page=page, 571 limit=limit, 572 ) 573 574 return self.factory.deserialize_activities(resp)
Fetch a Destiny 2 activity for the specified character id.
Parameters
- member_id (
int): The user id that starts with4611. - character_id (
int): The id of the character to retrieve the activities for. - mode (
aiobungie.typedefs.IntAnd[GameMode]): This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc.
Other Parameters
- membership_type (
MembershipType): The Member ship type, if nothing was passed than it will return all. - page (int):
The page number. Default is
0 - limit (int):
Limit the returned result. Default is
250.
Returns
aiobungie.iterators.Iterator[aiobungie.crates.Activity]: An iterator of the player's activities.
Raises
aiobungie.MembershipTypeError: The provided membership type was invalid.
576 async def fetch_post_activity(self, instance_id: int, /) -> activity.PostActivity: 577 """Fetch a post activity details. 578 579 Parameters 580 ---------- 581 instance_id: `int` 582 The activity instance id. 583 584 Returns 585 ------- 586 `aiobungie.crates.PostActivity` 587 A post activity object. 588 """ 589 resp = await self.rest.fetch_post_activity(instance_id) 590 591 return self.factory.deserialize_post_activity(resp)
Fetch a post activity details.
Parameters
- instance_id (
int): The activity instance id.
Returns
aiobungie.crates.PostActivity: A post activity object.
593 async def fetch_aggregated_activity_stats( 594 self, 595 character_id: int, 596 membership_id: int, 597 membership_type: typedefs.IntAnd[enums.MembershipType], 598 ) -> iterators.Iterator[activity.AggregatedActivity]: 599 """Fetch aggregated activity stats for a character. 600 601 Parameters 602 ---------- 603 character_id: `int` 604 The id of the character to retrieve the activities for. 605 membership_id: `int` 606 The id of the user that started with `4611`. 607 membership_type: `aiobungie.internal.enums.MembershipType` 608 The Member ship type. 609 610 Returns 611 ------- 612 `aiobungie.iterators.Iterator[aiobungie.crates.AggregatedActivity]` 613 An iterator of the player's activities. 614 615 Raises 616 ------ 617 `aiobungie.MembershipTypeError` 618 The provided membership type was invalid. 619 """ 620 resp = await self.rest.fetch_aggregated_activity_stats( 621 character_id, membership_id, membership_type 622 ) 623 624 return self.factory.deserialize_aggregated_activities(resp)
Fetch aggregated activity stats for a character.
Parameters
- character_id (
int): The id of the character to retrieve the activities for. - membership_id (
int): The id of the user that started with4611. - membership_type (
MembershipType): The Member ship type.
Returns
aiobungie.iterators.Iterator[aiobungie.crates.AggregatedActivity]: An iterator of the player's activities.
Raises
aiobungie.MembershipTypeError: The provided membership type was invalid.
628 async def fetch_clan_from_id( 629 self, 630 id: int, 631 /, 632 access_token: typing.Optional[str] = None, 633 ) -> clans.Clan: 634 """Fetch a Bungie Clan by its id. 635 636 Parameters 637 ----------- 638 id: `int` 639 The clan id. 640 641 Returns 642 -------- 643 `aiobungie.crates.Clan` 644 An Bungie clan. 645 646 Raises 647 ------ 648 `aiobungie.NotFound` 649 The clan was not found. 650 """ 651 resp = await self.rest.fetch_clan_from_id(id, access_token) 652 653 return self.factory.deserialize_clan(resp)
Fetch a Bungie Clan by its id.
Parameters
- id (
int): The clan id.
Returns
aiobungie.crates.Clan: An Bungie clan.
Raises
aiobungie.NotFound: The clan was not found.
655 async def fetch_clan( 656 self, 657 name: str, 658 /, 659 access_token: typing.Optional[str] = None, 660 *, 661 type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 662 ) -> clans.Clan: 663 """Fetch a Clan by its name. 664 This method will return the first clan found with given name. 665 666 Parameters 667 ---------- 668 name: `str` 669 The clan name 670 671 Other Parameters 672 ---------------- 673 access_token : `typing.Optional[str]` 674 An optional access token to make the request with. 675 676 If the token was bound to a member of the clan, 677 This field `aiobungie.crates.Clan.current_user_membership` will be available 678 and will return the membership of the user who made this request. 679 type : `aiobungie.GroupType` 680 The group type, Default is aiobungie.GroupType.CLAN. 681 682 Returns 683 ------- 684 `aiobungie.crates.Clan` 685 A Bungie clan. 686 687 Raises 688 ------ 689 `aiobungie.NotFound` 690 The clan was not found. 691 """ 692 resp = await self.rest.fetch_clan(name, access_token, type=type) 693 694 return self.factory.deserialize_clan(resp)
Fetch a Clan by its name. This method will return the first clan found with given name.
Parameters
- name (
str): The clan name
Other Parameters
access_token (
typing.Optional[str]): An optional access token to make the request with.If the token was bound to a member of the clan, This field
aiobungie.crates.Clan.current_user_membershipwill be available and will return the membership of the user who made this request.- type (
aiobungie.GroupType): The group type, Default is aiobungie.GroupType.CLAN.
Returns
aiobungie.crates.Clan: A Bungie clan.
Raises
aiobungie.NotFound: The clan was not found.
696 async def fetch_clan_conversations( 697 self, clan_id: int, / 698 ) -> collections.Sequence[clans.ClanConversation]: 699 """Fetch the conversations/chat channels of the given clan id. 700 701 Parameters 702 ---------- 703 clan_id : `int` 704 The clan id. 705 706 Returns 707 `collections.Sequence[aiobungie.crates.ClanConversation]` 708 A sequence of the clan chat channels. 709 """ 710 resp = await self.rest.fetch_clan_conversations(clan_id) 711 712 return self.factory.deserialize_clan_conversations(resp)
Fetch the conversations/chat channels of the given clan id.
Parameters
- clan_id (
int): The clan id. - Returns
collections.Sequence[aiobungie.crates.ClanConversation]: A sequence of the clan chat channels.
714 async def fetch_clan_admins( 715 self, clan_id: int, / 716 ) -> iterators.Iterator[clans.ClanMember]: 717 """Fetch the clan founder and admins. 718 719 Parameters 720 ---------- 721 clan_id : `int` 722 The clan id. 723 724 Returns 725 ------- 726 `aiobungie.iterators.Iterator[aiobungie.crates.ClanMember]` 727 An iterator over the found clan admins and founder. 728 729 Raises 730 ------ 731 `aiobungie.NotFound` 732 The requested clan was not found. 733 """ 734 resp = await self.rest.fetch_clan_admins(clan_id) 735 736 return self.factory.deserialize_clan_members(resp)
Fetch the clan founder and admins.
Parameters
- clan_id (
int): The clan id.
Returns
aiobungie.iterators.Iterator[aiobungie.crates.ClanMember]: An iterator over the found clan admins and founder.
Raises
aiobungie.NotFound: The requested clan was not found.
738 async def fetch_groups_for_member( 739 self, 740 member_id: int, 741 member_type: typedefs.IntAnd[enums.MembershipType], 742 /, 743 *, 744 filter: int = 0, 745 group_type: enums.GroupType = enums.GroupType.CLAN, 746 ) -> collections.Sequence[clans.GroupMember]: 747 """Fetch information about the groups that a given member has joined. 748 749 Parameters 750 ---------- 751 member_id : `int` 752 The member's id 753 member_type : `aiobungie.MembershipType` 754 The member's membership type. 755 756 Other Parameters 757 ---------------- 758 filter : `int` 759 Filter apply to list of joined groups. This Default to `0` 760 group_type : `aiobungie.GroupType` 761 The group's type. 762 This is always set to `aiobungie.GroupType.CLAN` and should not be changed. 763 764 Returns 765 ------- 766 `collections.Sequence[aiobungie.crates.GroupMember]` 767 A sequence of joined groups for the fetched member. 768 """ 769 resp = await self.rest.fetch_groups_for_member( 770 member_id, member_type, filter=filter, group_type=group_type 771 ) 772 773 return [ 774 self.factory.deserialize_group_member(group) for group in resp["results"] 775 ]
Fetch information about the groups that a given member has joined.
Parameters
- member_id (
int): The member's id - member_type (
aiobungie.MembershipType): The member's membership type.
Other Parameters
- filter (
int): Filter apply to list of joined groups. This Default to0 - group_type (
aiobungie.GroupType): The group's type. This is always set toaiobungie.GroupType.CLANand should not be changed.
Returns
collections.Sequence[aiobungie.crates.GroupMember]: A sequence of joined groups for the fetched member.
777 async def fetch_potential_groups_for_member( 778 self, 779 member_id: int, 780 member_type: typedefs.IntAnd[enums.MembershipType], 781 /, 782 *, 783 filter: int = 0, 784 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 785 ) -> collections.Sequence[clans.GroupMember]: 786 """Fetch the potential groups for a clan member. 787 788 Parameters 789 ---------- 790 member_id : `int` 791 The member's id 792 member_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]` 793 The member's membership type. 794 795 Other Parameters 796 ---------------- 797 filter : `int` 798 Filter apply to list of joined groups. This Default to `0` 799 group_type : `aiobungie.typedefs.IntAnd[aiobungie.GroupType]` 800 The group's type. 801 This is always set to `aiobungie.GroupType.CLAN` and should not be changed. 802 803 Returns 804 ------- 805 `collections.Sequence[aiobungie.crates.GroupMember]` 806 A sequence of joined potential groups for the fetched member. 807 """ 808 resp = await self.rest.fetch_potential_groups_for_member( 809 member_id, member_type, filter=filter, group_type=group_type 810 ) 811 812 return [ 813 self.factory.deserialize_group_member(group) for group in resp["results"] 814 ]
Fetch the potential groups for a clan member.
Parameters
- member_id (
int): The member's id - member_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Other Parameters
- filter (
int): Filter apply to list of joined groups. This Default to0 - group_type (
aiobungie.typedefs.IntAnd[aiobungie.GroupType]): The group's type. This is always set toaiobungie.GroupType.CLANand should not be changed.
Returns
collections.Sequence[aiobungie.crates.GroupMember]: A sequence of joined potential groups for the fetched member.
816 async def fetch_clan_members( 817 self, 818 clan_id: int, 819 /, 820 *, 821 name: typing.Optional[str] = None, 822 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 823 ) -> iterators.Iterator[clans.ClanMember]: 824 """Fetch Bungie clan members. 825 826 Parameters 827 ---------- 828 clan_id : `int` 829 The clans id 830 831 Other Parameters 832 ---------------- 833 name : `typing.Optional[str]` 834 If provided, Only players matching this name will be returned. 835 type : `aiobungie.MembershipType` 836 An optional clan member's membership type. 837 This parameter is used to filter the returned results 838 by the provided membership, For an example XBox memberships only, 839 Otherwise will return all memberships. 840 841 Returns 842 ------- 843 `aiobungie.iterators.Iterator[aiobungie.crates.ClanMember]` 844 An iterator over the bungie clan members. 845 846 Raises 847 ------ 848 `aiobungie.NotFound` 849 The clan was not found. 850 """ 851 resp = await self.rest.fetch_clan_members(clan_id, type=type, name=name) 852 853 return self.factory.deserialize_clan_members(resp)
Fetch Bungie clan members.
Parameters
- clan_id (
int): The clans id
Other Parameters
- name (
typing.Optional[str]): If provided, Only players matching this name will be returned. - type (
aiobungie.MembershipType): An optional clan member's membership type. This parameter is used to filter the returned results by the provided membership, For an example XBox memberships only, Otherwise will return all memberships.
Returns
aiobungie.iterators.Iterator[aiobungie.crates.ClanMember]: An iterator over the bungie clan members.
Raises
aiobungie.NotFound: The clan was not found.
868 async def kick_clan_member( 869 self, 870 access_token: str, 871 /, 872 group_id: int, 873 membership_id: int, 874 membership_type: typedefs.IntAnd[enums.MembershipType], 875 ) -> clans.Clan: 876 """Kick a member from the clan. 877 878 .. note:: 879 This request requires OAuth2: oauth2: `AdminGroups` scope. 880 881 Parameters 882 ---------- 883 access_token : `str` 884 The bearer access token associated with the bungie account. 885 group_id: `int` 886 The group id. 887 membership_id : `int` 888 The member id to kick. 889 membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]` 890 The member's membership type. 891 892 Returns 893 ------- 894 `aiobungie.crates.clan.Clan` 895 The clan that the member was kicked from. 896 """ 897 resp = await self.rest.kick_clan_member( 898 access_token, 899 group_id=group_id, 900 membership_id=membership_id, 901 membership_type=membership_type, 902 ) 903 904 return self.factory.deserialize_clan(resp)
Kick a member from the clan.
This request requires OAuth2: oauth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group id. - membership_id (
int): The member id to kick. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Returns
aiobungie.crates.clan.Clan: The clan that the member was kicked from.
906 async def fetch_clan_weekly_rewards(self, clan_id: int) -> milestones.Milestone: 907 """Fetch a Bungie clan's weekly reward state. 908 909 Parameters 910 ---------- 911 clan_id : `int` 912 The clan's id. 913 914 Returns 915 ------- 916 `aiobungie.crates.Milestone` 917 A runtime status of the clan's milestone data. 918 """ 919 920 resp = await self.rest.fetch_clan_weekly_rewards(clan_id) 921 922 return self.factory.deserialize_milestone(resp)
Fetch a Bungie clan's weekly reward state.
Parameters
- clan_id (
int): The clan's id.
Returns
aiobungie.crates.Milestone: A runtime status of the clan's milestone data.
926 async def fetch_inventory_item(self, hash: int, /) -> entity.InventoryEntity: 927 """Fetch a static inventory item entity given a its hash. 928 929 Parameters 930 ---------- 931 hash: `int` 932 Inventory item's hash. 933 934 Returns 935 ------- 936 `aiobungie.crates.InventoryEntity` 937 A bungie inventory item. 938 """ 939 resp = await self.rest.fetch_inventory_item(hash) 940 941 return self.factory.deserialize_inventory_entity(resp)
Fetch a static inventory item entity given a its hash.
Parameters
- hash (
int): Inventory item's hash.
Returns
aiobungie.crates.InventoryEntity: A bungie inventory item.
943 async def fetch_objective_entity(self, hash: int, /) -> entity.ObjectiveEntity: 944 """Fetch a Destiny objective entity given a its hash. 945 946 Parameters 947 ---------- 948 hash: `int` 949 objective's hash. 950 951 Returns 952 ------- 953 `aiobungie.crates.ObjectiveEntity` 954 An objective entity item. 955 """ 956 resp = await self.rest.fetch_objective_entity(hash) 957 958 return self.factory.deserialize_objective_entity(resp)
Fetch a Destiny objective entity given a its hash.
Parameters
- hash (
int): objective's hash.
Returns
aiobungie.crates.ObjectiveEntity: An objective entity item.
960 async def search_entities( 961 self, name: str, entity_type: str, *, page: int = 0 962 ) -> iterators.Iterator[entity.SearchableEntity]: 963 """Search for Destiny2 entities given a name and its type. 964 965 Parameters 966 ---------- 967 name : `str` 968 The name of the entity, i.e., Thunderlord, One thousand voices. 969 entity_type : `str` 970 The type of the entity, AKA Definition, 971 For an example `DestinyInventoryItemDefinition` for emblems, weapons, and other inventory items. 972 973 Other Parameters 974 ---------------- 975 page : `int` 976 An optional page to return. Default to 0. 977 978 Returns 979 ------- 980 `aiobungie.iterators.Iterator[aiobungie.crates.SearchableEntity]` 981 An iterator over the found results matching the provided name. 982 """ 983 resp = await self.rest.search_entities(name, entity_type, page=page) 984 985 return self.factory.deserialize_inventory_results(resp)
Search for Destiny2 entities given a name and its type.
Parameters
- name (
str): The name of the entity, i.e., Thunderlord, One thousand voices. - entity_type (
str): The type of the entity, AKA Definition, For an exampleDestinyInventoryItemDefinitionfor emblems, weapons, and other inventory items.
Other Parameters
- page (
int): An optional page to return. Default to 0.
Returns
aiobungie.iterators.Iterator[aiobungie.crates.SearchableEntity]: An iterator over the found results matching the provided name.
989 async def fetch_fireteams( 990 self, 991 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 992 *, 993 platform: typedefs.IntAnd[ 994 fireteams.FireteamPlatform 995 ] = fireteams.FireteamPlatform.ANY, 996 language: typing.Union[ 997 fireteams.FireteamLanguage, str 998 ] = fireteams.FireteamLanguage.ALL, 999 date_range: int = 0, 1000 page: int = 0, 1001 slots_filter: int = 0, 1002 ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]: 1003 """Fetch public Bungie fireteams with open slots. 1004 1005 Parameters 1006 ---------- 1007 activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]` 1008 The fireteam activity type. 1009 1010 Other Parameters 1011 ---------------- 1012 platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]` 1013 If this is provided. Then the results will be filtered with the given platform. 1014 Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms. 1015 language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]` 1016 A locale language to filter the used language in that fireteam. 1017 Defaults to `aiobungie.crates.FireteamLanguage.ALL` 1018 date_range : `int` 1019 An integer to filter the date range of the returned fireteams. Defaults to `aiobungie.FireteamDate.ALL`. 1020 page : `int` 1021 The page number. By default its `0` which returns all available activities. 1022 slots_filter : `int` 1023 Filter the returned fireteams based on available slots. Default is `0` 1024 1025 Returns 1026 ------- 1027 `typing.Optional[collections.Sequence[fireteams.Fireteam]]` 1028 A sequence of `aiobungie.crates.Fireteam` or `None`. 1029 """ 1030 1031 resp = await self.rest.fetch_fireteams( 1032 activity_type, 1033 platform=platform, 1034 language=language, 1035 date_range=date_range, 1036 page=page, 1037 slots_filter=slots_filter, 1038 ) 1039 1040 return self.factory.deserialize_fireteams(resp)
Fetch public Bungie fireteams with open slots.
Parameters
- activity_type (
aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]): The fireteam activity type.
Other Parameters
- platform (
aiobungie.typedefs.IntAnd[FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults toaiobungie.crates.FireteamPlatform.ANYwhich returns all platforms. - language (
typing.Union[FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults toaiobungie.crates.FireteamLanguage.ALL - date_range (
int): An integer to filter the date range of the returned fireteams. Defaults toaiobungie.FireteamDate.ALL. - page (
int): The page number. By default its0which returns all available activities. - slots_filter (
int): Filter the returned fireteams based on available slots. Default is0
Returns
typing.Optional[collections.Sequence[fireteams.Fireteam]]: A sequence ofaiobungie.crates.FireteamorNone.
1042 async def fetch_available_clan_fireteams( 1043 self, 1044 access_token: str, 1045 group_id: int, 1046 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 1047 *, 1048 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1049 language: typing.Union[fireteams.FireteamLanguage, str], 1050 date_range: int = 0, 1051 page: int = 0, 1052 public_only: bool = False, 1053 slots_filter: int = 0, 1054 ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]: 1055 """Fetch a clan's fireteams with open slots. 1056 1057 .. note:: 1058 This method requires OAuth2: ReadGroups scope. 1059 1060 Parameters 1061 ---------- 1062 access_token : `str` 1063 The bearer access token associated with the bungie account. 1064 group_id : `int` 1065 The group/clan id of the fireteam. 1066 activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]` 1067 The fireteam activity type. 1068 1069 Other Parameters 1070 ---------------- 1071 platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]` 1072 If this is provided. Then the results will be filtered with the given platform. 1073 Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms. 1074 language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]` 1075 A locale language to filter the used language in that fireteam. 1076 Defaults to `aiobungie.crates.FireteamLanguage.ALL` 1077 date_range : `int` 1078 An integer to filter the date range of the returned fireteams. Defaults to `0`. 1079 page : `int` 1080 The page number. By default its `0` which returns all available activities. 1081 public_only: `bool` 1082 If set to True, Then only public fireteams will be returned. 1083 slots_filter : `int` 1084 Filter the returned fireteams based on available slots. Default is `0` 1085 1086 Returns 1087 ------- 1088 `typing.Optional[collections.Sequence[aiobungie.crates.Fireteam]]` 1089 A sequence of fireteams found in the clan. 1090 `None` will be returned if nothing was found. 1091 """ 1092 resp = await self.rest.fetch_available_clan_fireteams( 1093 access_token, 1094 group_id, 1095 activity_type, 1096 platform=platform, 1097 language=language, 1098 date_range=date_range, 1099 page=page, 1100 public_only=public_only, 1101 slots_filter=slots_filter, 1102 ) 1103 1104 return self.factory.deserialize_fireteams(resp)
Fetch a clan's fireteams with open slots.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group/clan id of the fireteam. - activity_type (
aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]): The fireteam activity type.
Other Parameters
- platform (
aiobungie.typedefs.IntAnd[FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults toaiobungie.crates.FireteamPlatform.ANYwhich returns all platforms. - language (
typing.Union[FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults toaiobungie.crates.FireteamLanguage.ALL - date_range (
int): An integer to filter the date range of the returned fireteams. Defaults to0. - page (
int): The page number. By default its0which returns all available activities. - public_only (
bool): If set to True, Then only public fireteams will be returned. - slots_filter (
int): Filter the returned fireteams based on available slots. Default is0
Returns
typing.Optional[collections.Sequence[aiobungie.crates.Fireteam]]: A sequence of fireteams found in the clan.Nonewill be returned if nothing was found.
1106 async def fetch_clan_fireteam( 1107 self, access_token: str, fireteam_id: int, group_id: int 1108 ) -> fireteams.AvailableFireteam: 1109 """Fetch a specific clan fireteam. 1110 1111 .. note:: 1112 This method requires OAuth2: ReadGroups scope. 1113 1114 Parameters 1115 ---------- 1116 access_token : `str` 1117 The bearer access token associated with the bungie account. 1118 group_id : `int` 1119 The group/clan id to fetch the fireteam from. 1120 fireteam_id : `int` 1121 The fireteam id to fetch. 1122 1123 Returns 1124 ------- 1125 `typing.Optional[aiobungie.crates.AvailableFireteam]` 1126 A sequence of available fireteams objects if exists. else `None` will be returned. 1127 """ 1128 resp = await self.rest.fetch_clan_fireteam(access_token, fireteam_id, group_id) 1129 1130 return self.factory.deserialize_available_fireteams(resp, no_results=True) # type: ignore[return-value]
Fetch a specific clan fireteam.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group/clan id to fetch the fireteam from. - fireteam_id (
int): The fireteam id to fetch.
Returns
typing.Optional[aiobungie.crates.AvailableFireteam]: A sequence of available fireteams objects if exists. elseNonewill be returned.
1132 async def fetch_my_clan_fireteams( 1133 self, 1134 access_token: str, 1135 group_id: int, 1136 *, 1137 include_closed: bool = True, 1138 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1139 language: typing.Union[fireteams.FireteamLanguage, str], 1140 filtered: bool = True, 1141 page: int = 0, 1142 ) -> collections.Sequence[fireteams.AvailableFireteam]: 1143 """A method that's similar to `fetch_fireteams` but requires OAuth2. 1144 1145 .. note:: 1146 This method requires OAuth2: ReadGroups scope. 1147 1148 Parameters 1149 ---------- 1150 access_token : str 1151 The bearer access token associated with the bungie account. 1152 group_id : int 1153 The group/clan id to fetch. 1154 1155 Other Parameters 1156 ---------------- 1157 include_closed : bool 1158 If provided and set to True, It will also return closed fireteams. 1159 If provided and set to False, It will only return public fireteams. Default is True. 1160 platform : aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform] 1161 If this is provided. Then the results will be filtered with the given platform. 1162 Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms. 1163 language : typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str] 1164 A locale language to filter the used language in that fireteam. 1165 Defaults to aiobungie.crates.FireteamLanguage.ALL 1166 filtered : bool 1167 If set to True, it will filter by clan. Otherwise not. Default is True. 1168 page : int 1169 The page number. By default its 0 which returns all available activities. 1170 1171 Returns 1172 ------- 1173 `collections.Sequence[aiobungie.crates.AvailableFireteam]` 1174 A sequence of available fireteams objects if exists. else `None` will be returned. 1175 """ 1176 resp = await self.rest.fetch_my_clan_fireteams( 1177 access_token, 1178 group_id, 1179 include_closed=include_closed, 1180 platform=platform, 1181 language=language, 1182 filtered=filtered, 1183 page=page, 1184 ) 1185 1186 return self.factory.deserialize_available_fireteams(resp) # type: ignore[return-value]
A method that's similar to fetch_fireteams but requires OAuth2.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (str): The bearer access token associated with the bungie account.
- group_id (int): The group/clan id to fetch.
Other Parameters
- include_closed (bool): If provided and set to True, It will also return closed fireteams. If provided and set to False, It will only return public fireteams. Default is True.
- platform (aiobungie.typedefs.IntAnd[FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
- language (typing.Union[FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
- filtered (bool): If set to True, it will filter by clan. Otherwise not. Default is True.
- page (int): The page number. By default its 0 which returns all available activities.
Returns
collections.Sequence[aiobungie.crates.AvailableFireteam]: A sequence of available fireteams objects if exists. elseNonewill be returned.
1190 async def fetch_friends( 1191 self, access_token: str, / 1192 ) -> collections.Sequence[friends.Friend]: 1193 """Fetch bungie friend list. 1194 1195 .. note:: 1196 This requests OAuth2: ReadUserData scope. 1197 1198 Parameters 1199 ----------- 1200 access_token : `str` 1201 The bearer access token associated with the bungie account. 1202 1203 Returns 1204 ------- 1205 `collections.Sequence[aiobungie.crates.Friend]` 1206 A sequence of the friends associated with that access token. 1207 """ 1208 1209 resp = await self.rest.fetch_friends(access_token) 1210 1211 return self.factory.deserialize_friends(resp)
Fetch bungie friend list.
This requests OAuth2: ReadUserData scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account.
Returns
collections.Sequence[aiobungie.crates.Friend]: A sequence of the friends associated with that access token.
1213 async def fetch_friend_requests( 1214 self, access_token: str, / 1215 ) -> friends.FriendRequestView: 1216 """Fetch pending bungie friend requests queue. 1217 1218 .. note:: 1219 This requests OAuth2: ReadUserData scope. 1220 1221 Parameters 1222 ----------- 1223 access_token : `str` 1224 The bearer access token associated with the bungie account. 1225 1226 Returns 1227 ------- 1228 `aiobungie.crates.FriendRequestView` 1229 A friend requests view of that associated access token. 1230 """ 1231 1232 resp = await self.rest.fetch_friend_requests(access_token) 1233 1234 return self.factory.deserialize_friend_requests(resp)
Fetch pending bungie friend requests queue.
This requests OAuth2: ReadUserData scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account.
Returns
aiobungie.crates.FriendRequestView: A friend requests view of that associated access token.
1238 async def fetch_application(self, appid: int, /) -> application.Application: 1239 """Fetch a Bungie application. 1240 1241 Parameters 1242 ----------- 1243 appid: `int` 1244 The application id. 1245 1246 Returns 1247 -------- 1248 `aiobungie.crates.Application` 1249 A Bungie application. 1250 """ 1251 resp = await self.rest.fetch_application(appid) 1252 1253 return self.factory.deserialize_app(resp)
Fetch a Bungie application.
Parameters
- appid (
int): The application id.
Returns
aiobungie.crates.Application: A Bungie application.
1257 async def fetch_public_milestone_content( 1258 self, milestone_hash: int, / 1259 ) -> milestones.MilestoneContent: 1260 """Fetch the milestone content given its hash. 1261 1262 Parameters 1263 ---------- 1264 milestone_hash : `int` 1265 The milestone hash. 1266 1267 Returns 1268 ------- 1269 `aiobungie.crates.milestones.MilestoneContent` 1270 A milestone content object. 1271 """ 1272 resp = await self.rest.fetch_public_milestone_content(milestone_hash) 1273 1274 return self.factory.deserialize_public_milestone_content(resp)
Fetch the milestone content given its hash.
Parameters
- milestone_hash (
int): The milestone hash.
Returns
aiobungie.crates.milestones.MilestoneContent: A milestone content object.
771@typing.final 772class ClosedReasons(Flag): 773 """A Flags enumeration representing the reasons why a person can't join this user's fireteam.""" 774 775 NONE = 0 776 MATCHMAKING = 1 << 0 777 LOADING = 1 << 1 778 SOLO = 1 << 2 779 """The activity is required to be played solo.""" 780 INTERNAL_REASONS = 1 << 3 781 """ 782 The user can't be joined for one of a variety of internal reasons. 783 Basically, the game can't let you join at this time, 784 but for reasons that aren't under the control of this user 785 """ 786 DISALLOWED_BY_GAME_STATE = 1 << 4 787 """The user's current activity/quest/other transitory game state is preventing joining.""" 788 OFFLINE = 32768 789 """The user appears offline."""
A Flags enumeration representing the reasons why a person can't join this user's fireteam.
The user can't be joined for one of a variety of internal reasons. Basically, the game can't let you join at this time, but for reasons that aren't under the control of this user
The user's current activity/quest/other transitory game state is preventing joining.
74@typing.final 75class ComponentFields(enums.Enum): 76 """An enum that provides fields found in a base component response.""" 77 78 PRIVACY = ComponentPrivacy.NONE 79 DISABLED = False
An enum that provides fields found in a base component response.
65@typing.final 66class ComponentPrivacy(int, enums.Enum): 67 """An enum the provides privacy settings for profile components.""" 68 69 NONE = 0 70 PUBLIC = 1 71 PRIVATE = 2
An enum the provides privacy settings for profile components.
348@typing.final 349class ComponentType(Enum): 350 """An Enum for Destiny 2 profile Components.""" 351 352 NONE = 0 353 354 PROFILE = 100 355 PROFILE_INVENTORIES = 102 356 PROFILE_CURRENCIES = 103 357 PROFILE_PROGRESSION = 104 358 ALL_PROFILES = ( 359 PROFILE, 360 PROFILE_INVENTORIES, 361 PROFILE_CURRENCIES, 362 PROFILE_PROGRESSION, 363 ) 364 """All profile components.""" 365 366 VENDORS = 400 367 VENDOR_SALES = 402 368 VENDOR_RECEIPTS = 101 369 ALL_VENDORS = (VENDORS, VENDOR_RECEIPTS, VENDOR_SALES) 370 """All vendor components.""" 371 372 # Items 373 ITEM_INSTANCES = 300 374 ITEM_OBJECTIVES = 301 375 ITEM_PERKS = 302 376 ITEM_RENDER_DATA = 303 377 ITEM_STATS = 304 378 ITEM_SOCKETS = 305 379 ITEM_TALENT_GRINDS = 306 380 ITEM_PLUG_STATES = 308 381 ITEM_PLUG_OBJECTIVES = 309 382 ITEM_REUSABLE_PLUGS = 310 383 384 ALL_ITEMS = ( 385 ITEM_PLUG_OBJECTIVES, 386 ITEM_PLUG_STATES, 387 ITEM_SOCKETS, 388 ITEM_INSTANCES, 389 ITEM_OBJECTIVES, 390 ITEM_PERKS, 391 ITEM_RENDER_DATA, 392 ITEM_STATS, 393 ITEM_TALENT_GRINDS, 394 ITEM_REUSABLE_PLUGS, 395 ) 396 """All item components.""" 397 398 PLATFORM_SILVER = 105 399 KIOSKS = 500 400 CURRENCY_LOOKUPS = 600 401 PRESENTATION_NODES = 700 402 COLLECTIBLES = 800 403 RECORDS = 900 404 TRANSITORY = 1000 405 METRICS = 1100 406 INVENTORIES = 102 407 STRING_VARIABLES = 1200 408 CRAFTABLES = 1300 409 410 CHARACTERS = 200 411 CHARACTER_INVENTORY = 201 412 CHARECTER_PROGRESSION = 202 413 CHARACTER_RENDER_DATA = 203 414 CHARACTER_ACTIVITIES = 204 415 CHARACTER_EQUIPMENT = 205 416 CHARACTER_LOADOUTS = 206 417 418 ALL_CHARACTERS = ( 419 CHARACTERS, 420 CHARACTER_INVENTORY, 421 CHARECTER_PROGRESSION, 422 CHARACTER_RENDER_DATA, 423 CHARACTER_ACTIVITIES, 424 CHARACTER_EQUIPMENT, 425 CHARACTER_LOADOUTS, 426 RECORDS, 427 ) 428 """All character components.""" 429 430 ALL = ( 431 *ALL_PROFILES, # type: ignore 432 *ALL_CHARACTERS, # type: ignore 433 *ALL_VENDORS, # type: ignore 434 *ALL_ITEMS, # type: ignore 435 RECORDS, 436 CURRENCY_LOOKUPS, 437 PRESENTATION_NODES, 438 COLLECTIBLES, 439 KIOSKS, 440 METRICS, 441 PLATFORM_SILVER, 442 INVENTORIES, 443 STRING_VARIABLES, 444 TRANSITORY, 445 CRAFTABLES, 446 ) 447 """ALl components included."""
An Enum for Destiny 2 profile Components.
All item components.
All character components.
ALl components included.
653@typing.final 654class CredentialType(int, Enum): 655 """The types of the accounts system supports at bungie.""" 656 657 NONE = 0 658 XUID = 1 659 PSNID = 2 660 WILD = 3 661 FAKE = 4 662 FACEBOOK = 5 663 GOOGLE = 8 664 WINDOWS = 9 665 DEMONID = 10 666 STEAMID = 12 667 BATTLENETID = 14 668 STADIAID = 16 669 TWITCHID = 18
The types of the accounts system supports at bungie.
531@typing.final 532class DamageType(int, Enum): 533 """Enums for Destiny Damage types""" 534 535 NONE = 0 536 KINETIC = 1 537 ARC = 2 538 SOLAR = 3 539 VOID = 4 540 RAID = 5 541 """This is a special damage type reserved for some raid activity encounters.""" 542 STASIS = 6
Enums for Destiny Damage types
This is a special damage type reserved for some raid activity encounters.
64@typing.final 65class Difficulty(int, enums.Enum): 66 """An enum for activities difficulties.""" 67 68 TRIVIAL = 0 69 EASY = 1 70 NORMAL = 2 71 CHALLENGING = 3 72 HARD = 4 73 BRAVE = 5 74 ALMOST_IMPOSSIBLE = 6 75 IMPOSSIBLE = 7
An enum for activities difficulties.
150@typing.final 151class Dungeon(int, Enum): 152 """An Enum for all available Dungeon/Like missions in Destiny 2.""" 153 154 NORMAL_PRESAGE = 2124066889 155 """Normal Presage""" 156 157 MASTER_PRESAGE = 4212753278 158 """Master Presage""" 159 160 HARBINGER = 1738383283 161 """Harbinger""" 162 163 PROPHECY = 4148187374 164 """Prophecy""" 165 166 MASTER_POH = 785700673 167 """Master Pit of Heresy?""" 168 169 LEGEND_POH = 785700678 170 """Legend Pit of Heresy?""" 171 172 POH = 1375089621 173 """Normal Pit of Heresy.""" 174 175 SHATTERED = 2032534090 176 """Shattered Throne""" 177 178 GOA_LEGEND = 4078656646 179 """Grasp of Avarice legend.""" 180 181 GOA_MASTER = 3774021532 182 """Grasp of Avarice master."""
An Enum for all available Dungeon/Like missions in Destiny 2.
70class Enum(__enum.Enum): 71 """Builtin Python enum with extra handlings.""" 72 73 @property 74 def name(self) -> str: # type: ignore[override] 75 return self._name_ 76 77 @property 78 def value(self) -> typing.Any: # type: ignore[override] 79 return self._value_ 80 81 def __str__(self) -> str: 82 return self._name_ 83 84 def __repr__(self) -> str: 85 return f"<{type(self).__name__}.{self._name_}: {self._value_!s}>" 86 87 def __int__(self) -> int: 88 return int(self.value)
Builtin Python enum with extra handlings.
61class Factory(interfaces.FactoryInterface): 62 """The base deserialization factory class for all aiobungie objects. 63 64 This entity factory is used to deserialize JSON responses from the REST client and turning them 65 into a `aiobungie.crates` Python classes. 66 """ 67 68 __slots__ = ("_net",) 69 70 def __init__(self, net: traits.Netrunner) -> None: 71 self._net = net 72 73 def deserialize_bungie_user(self, data: typedefs.JSONObject) -> user.BungieUser: 74 return user.BungieUser( 75 id=int(data["membershipId"]), 76 created_at=time.clean_date(data["firstAccess"]), 77 name=data.get("cachedBungieGlobalDisplayName", undefined.UNDEFINED), 78 is_deleted=data["isDeleted"], 79 about=data["about"], 80 updated_at=time.clean_date(data["lastUpdate"]), 81 psn_name=data.get("psnDisplayName", None), 82 stadia_name=data.get("stadiaDisplayName", None), 83 steam_name=data.get("steamDisplayName", None), 84 twitch_name=data.get("twitchDisplayName", None), 85 blizzard_name=data.get("blizzardDisplayName", None), 86 status=data["statusText"], 87 locale=data["locale"], 88 picture=assets.Image(path=str(data["profilePicturePath"])), 89 code=data.get("cachedBungieGlobalDisplayNameCode", None), 90 unique_name=data.get("uniqueName", None), 91 theme_id=int(data["profileTheme"]), 92 show_activity=bool(data["showActivity"]), 93 theme_name=data["profileThemeName"], 94 display_title=data["userTitleDisplay"], 95 ) 96 97 def deserialize_partial_bungie_user( 98 self, payload: typedefs.JSONObject 99 ) -> user.PartialBungieUser: 100 return user.PartialBungieUser( 101 net=self._net, 102 types=[ 103 enums.MembershipType(type_) 104 for type_ in payload.get("applicableMembershipTypes", []) 105 ], 106 name=payload.get("displayName", undefined.UNDEFINED), 107 id=int(payload["membershipId"]), 108 crossave_override=enums.MembershipType(payload["crossSaveOverride"]), 109 is_public=payload["isPublic"], 110 icon=assets.Image(payload.get("iconPath", "")), 111 type=enums.MembershipType(payload["membershipType"]), 112 ) 113 114 def deserialize_destiny_membership( 115 self, payload: typedefs.JSONObject 116 ) -> user.DestinyMembership: 117 name: undefined.UndefinedOr[str] = undefined.UNDEFINED 118 if ( 119 raw_name := payload.get("bungieGlobalDisplayName", "") 120 ) and not typedefs.is_unknown(raw_name): 121 name = raw_name 122 123 return user.DestinyMembership( 124 net=self._net, 125 id=int(payload["membershipId"]), 126 name=name, 127 code=payload.get("bungieGlobalDisplayNameCode", None), 128 last_seen_name=payload.get("LastSeenDisplayName") 129 or payload.get("displayName") # noqa: W503 130 or "", # noqa: W503 131 type=enums.MembershipType(payload["membershipType"]), 132 is_public=payload["isPublic"], 133 crossave_override=enums.MembershipType(payload["crossSaveOverride"]), 134 icon=assets.Image(payload.get("iconPath", "")), 135 types=[ 136 enums.MembershipType(type_) 137 for type_ in payload.get("applicableMembershipTypes", []) 138 ], 139 ) 140 141 def deserialize_destiny_memberships( 142 self, data: typedefs.JSONArray 143 ) -> collections.Sequence[user.DestinyMembership]: 144 return [self.deserialize_destiny_membership(membership) for membership in data] 145 146 def deserialize_user(self, data: typedefs.JSONObject) -> user.User: 147 primary_membership_id: typing.Optional[int] = None 148 if raw_primary_id := data.get("primaryMembershipId"): 149 primary_membership_id = int(raw_primary_id) 150 151 return user.User( 152 bungie=self.deserialize_bungie_user(data["bungieNetUser"]), 153 destiny=self.deserialize_destiny_memberships(data["destinyMemberships"]), 154 primary_membership_id=primary_membership_id, 155 ) 156 157 def deserialize_searched_user( 158 self, payload: typedefs.JSONObject 159 ) -> user.SearchableDestinyUser: 160 name: undefined.UndefinedOr[str] = undefined.UNDEFINED 161 if (raw_name := payload["bungieGlobalDisplayName"]) and not typedefs.is_unknown( 162 raw_name 163 ): 164 name = raw_name 165 166 code: typing.Optional[int] = None 167 if raw_code := payload.get("bungieGlobalDisplayNameCode"): 168 code = int(raw_code) 169 170 bungie_id: typing.Optional[int] = None 171 if raw_bungie_id := payload.get("bungieNetMembershipId"): 172 bungie_id = int(raw_bungie_id) 173 174 return user.SearchableDestinyUser( 175 name=name, 176 code=code, 177 bungie_id=bungie_id, 178 memberships=self.deserialize_destiny_memberships( 179 payload["destinyMemberships"] 180 ), 181 ) 182 183 def deserialize_user_credentials( 184 self, payload: typedefs.JSONArray 185 ) -> collections.Sequence[user.UserCredentials]: 186 return [ 187 user.UserCredentials( 188 type=enums.CredentialType(int(creds["credentialType"])), 189 display_name=creds["credentialDisplayName"], 190 is_public=creds["isPublic"], 191 self_as_string=creds.get("credentialAsString", undefined.UNDEFINED), 192 ) 193 for creds in payload 194 ] 195 196 def deserialize_user_themes( 197 self, payload: typedefs.JSONArray 198 ) -> collections.Sequence[user.UserThemes]: 199 return [ 200 user.UserThemes( 201 id=int(entry["userThemeId"]), 202 name=entry["userThemeName"] 203 if "userThemeName" in entry 204 else undefined.UNDEFINED, 205 description=entry["userThemeDescription"] 206 if "userThemeDescription" in entry 207 else undefined.UNDEFINED, 208 ) 209 for entry in payload 210 ] 211 212 def deserialize_clan(self, payload: typedefs.JSONObject) -> clans.Clan: 213 # This is kinda redundant 214 data = payload 215 216 # This is always outside the details. 217 current_user_map: typing.Optional[ 218 collections.Mapping[str, clans.ClanMember] 219 ] = None 220 if raw_current_user_map := payload.get("currentUserMemberMap"): 221 current_user_map = { 222 membership_type: self.deserialize_clan_member(membership) 223 for membership_type, membership in raw_current_user_map.items() 224 } 225 226 try: 227 data = payload["detail"] 228 except KeyError: 229 pass 230 231 id = data["groupId"] 232 name = data["name"] 233 created_at = data["creationDate"] 234 member_count = data["memberCount"] 235 about = data["about"] 236 motto = data["motto"] 237 is_public = data["isPublic"] 238 banner = assets.Image(str(data["bannerPath"])) 239 avatar = assets.Image(str(data["avatarPath"])) 240 tags = data["tags"] 241 type = data["groupType"] 242 243 features = data["features"] 244 features_obj = clans.ClanFeatures( 245 max_members=features["maximumMembers"], 246 max_membership_types=features["maximumMembershipsOfGroupType"], 247 capabilities=features["capabilities"], 248 membership_types=features["membershipTypes"], 249 invite_permissions=features["invitePermissionOverride"], 250 update_banner_permissions=features["updateBannerPermissionOverride"], 251 update_culture_permissions=features["updateCulturePermissionOverride"], 252 join_level=features["joinLevel"], 253 ) 254 255 information: typedefs.JSONObject = data["clanInfo"] 256 progression: collections.Mapping[int, progressions.Progression] = { 257 int(prog_hash): self.deserialize_progressions(prog) 258 for prog_hash, prog in information["d2ClanProgressions"].items() 259 } 260 261 founder: typedefs.NoneOr[clans.ClanMember] = None 262 if raw_founder := payload.get("founder"): 263 founder = self.deserialize_clan_member(raw_founder) 264 265 return clans.Clan( 266 net=self._net, 267 id=int(id), 268 name=name, 269 type=enums.GroupType(type), 270 created_at=time.clean_date(created_at), 271 member_count=member_count, 272 motto=motto, 273 about=about, 274 is_public=is_public, 275 banner=banner, 276 avatar=avatar, 277 tags=tags, 278 features=features_obj, 279 owner=founder, 280 progressions=progression, 281 call_sign=information["clanCallsign"], 282 banner_data=information["clanBannerData"], 283 chat_security=data["chatSecurity"], 284 conversation_id=int(data["conversationId"]), 285 allow_chat=data["allowChat"], 286 theme=data["theme"], 287 current_user_membership=current_user_map, 288 ) 289 290 def deserialize_clan_member(self, data: typedefs.JSONObject, /) -> clans.ClanMember: 291 destiny_user = self.deserialize_destiny_membership(data["destinyUserInfo"]) 292 return clans.ClanMember( 293 net=self._net, 294 last_seen_name=destiny_user.last_seen_name, 295 id=destiny_user.id, 296 name=destiny_user.name, 297 icon=destiny_user.icon, 298 last_online=time.from_timestamp(int(data["lastOnlineStatusChange"])), 299 group_id=int(data["groupId"]), 300 joined_at=time.clean_date(data["joinDate"]), 301 types=destiny_user.types, 302 is_public=destiny_user.is_public, 303 type=destiny_user.type, 304 code=destiny_user.code, 305 is_online=data["isOnline"], 306 crossave_override=destiny_user.crossave_override, 307 bungie=self.deserialize_partial_bungie_user(data["bungieNetUserInfo"]) 308 if "bungieNetUserInfo" in data 309 else None, 310 member_type=enums.ClanMemberType(int(data["memberType"])), 311 ) 312 313 def deserialize_clan_members( 314 self, data: typedefs.JSONObject, / 315 ) -> iterators.Iterator[clans.ClanMember]: 316 return iterators.Iterator( 317 [self.deserialize_clan_member(member) for member in data["results"]] 318 ) 319 320 def deserialize_group_member( 321 self, payload: typedefs.JSONObject 322 ) -> clans.GroupMember: 323 member = payload["member"] 324 return clans.GroupMember( 325 net=self._net, 326 join_date=time.clean_date(member["joinDate"]), 327 group_id=int(member["groupId"]), 328 member_type=enums.ClanMemberType(member["memberType"]), 329 is_online=member["isOnline"], 330 last_online=time.from_timestamp(int(member["lastOnlineStatusChange"])), 331 inactive_memberships=payload.get("areAllMembershipsInactive", None), 332 member=self.deserialize_destiny_membership(member["destinyUserInfo"]), 333 group=self.deserialize_clan(payload["group"]), 334 ) 335 336 def _deserialize_clan_conversation( 337 self, payload: typedefs.JSONObject 338 ) -> clans.ClanConversation: 339 return clans.ClanConversation( 340 net=self._net, 341 id=int(payload["conversationId"]), 342 group_id=int(payload["groupId"]), 343 name=( 344 payload["chatName"] 345 if not typedefs.is_unknown(payload["chatName"]) 346 else undefined.UNDEFINED 347 ), 348 chat_enabled=payload["chatEnabled"], 349 security=payload["chatSecurity"], 350 ) 351 352 def deserialize_clan_conversations( 353 self, payload: typedefs.JSONArray 354 ) -> collections.Sequence[clans.ClanConversation]: 355 return [self._deserialize_clan_conversation(conv) for conv in payload] 356 357 def deserialize_app_owner( 358 self, payload: typedefs.JSONObject 359 ) -> application.ApplicationOwner: 360 return application.ApplicationOwner( 361 net=self._net, 362 name=payload.get("bungieGlobalDisplayName", undefined.UNDEFINED), 363 id=int(payload["membershipId"]), 364 type=enums.MembershipType(payload["membershipType"]), 365 icon=assets.Image(str(payload["iconPath"])), 366 is_public=payload["isPublic"], 367 code=payload.get("bungieGlobalDisplayNameCode", None), 368 ) 369 370 def deserialize_app(self, payload: typedefs.JSONObject) -> application.Application: 371 return application.Application( 372 id=int(payload["applicationId"]), 373 name=payload["name"], 374 link=payload["link"], 375 status=payload["status"], 376 redirect_url=payload.get("redirectUrl", None), 377 created_at=time.clean_date(str(payload["creationDate"])), 378 published_at=time.clean_date(str(payload["firstPublished"])), 379 owner=self.deserialize_app_owner(payload["team"][0]["user"]), # type: ignore 380 scope=payload.get("scope", undefined.UNDEFINED), 381 ) 382 383 def _set_character_attrs(self, payload: typedefs.JSONObject) -> character.Character: 384 return character.Character( 385 net=self._net, 386 id=int(payload["characterId"]), 387 gender=enums.Gender(payload["genderType"]), 388 race=enums.Race(payload["raceType"]), 389 class_type=enums.Class(payload["classType"]), 390 emblem=assets.Image(str(payload["emblemBackgroundPath"])), 391 emblem_icon=assets.Image(str(payload["emblemPath"])), 392 emblem_hash=int(payload["emblemHash"]), 393 last_played=time.clean_date(payload["dateLastPlayed"]), 394 total_played_time=int(payload["minutesPlayedTotal"]), 395 member_id=int(payload["membershipId"]), 396 member_type=enums.MembershipType(payload["membershipType"]), 397 level=payload["baseCharacterLevel"], 398 title_hash=payload.get("titleRecordHash", None), 399 light=payload["light"], 400 stats={enums.Stat(int(k)): v for k, v in payload["stats"].items()}, 401 ) 402 403 def deserialize_profile(self, payload: typedefs.JSONObject, /) -> profile.Profile: 404 payload = payload["data"] 405 id = int(payload["userInfo"]["membershipId"]) 406 name = payload["userInfo"]["displayName"] 407 is_public = payload["userInfo"]["isPublic"] 408 type = enums.MembershipType(payload["userInfo"]["membershipType"]) 409 last_played = time.clean_date(str(payload["dateLastPlayed"])) 410 character_ids = [int(cid) for cid in payload["characterIds"]] 411 power_cap = payload["currentSeasonRewardPowerCap"] 412 413 return profile.Profile( 414 id=int(id), 415 name=name, 416 is_public=is_public, 417 type=type, 418 last_played=last_played, 419 character_ids=character_ids, 420 power_cap=power_cap, 421 net=self._net, 422 ) 423 424 def deserialize_profile_item( 425 self, payload: typedefs.JSONObject 426 ) -> profile.ProfileItemImpl: 427 instance_id: typing.Optional[int] = None 428 if raw_instance_id := payload.get("itemInstanceId"): 429 instance_id = int(raw_instance_id) 430 431 version_number: typing.Optional[int] = None 432 if raw_version := payload.get("versionNumber"): 433 version_number = int(raw_version) 434 435 transfer_status = enums.TransferStatus(payload["transferStatus"]) 436 437 return profile.ProfileItemImpl( 438 net=self._net, 439 hash=payload["itemHash"], 440 quantity=payload["quantity"], 441 bind_status=enums.ItemBindStatus(payload["bindStatus"]), 442 location=enums.ItemLocation(payload["location"]), 443 bucket=payload["bucketHash"], 444 transfer_status=transfer_status, 445 lockable=payload["lockable"], 446 state=enums.ItemState(payload["state"]), 447 dismantle_permissions=payload["dismantlePermission"], 448 is_wrapper=payload["isWrapper"], 449 instance_id=instance_id, 450 version_number=version_number, 451 ornament_id=payload.get("overrideStyleItemHash"), 452 ) 453 454 def deserialize_objectives(self, payload: typedefs.JSONObject) -> records.Objective: 455 return records.Objective( 456 net=self._net, 457 hash=payload["objectiveHash"], 458 visible=payload["visible"], 459 complete=payload["complete"], 460 completion_value=payload["completionValue"], 461 progress=payload.get("progress"), 462 destination_hash=payload.get("destinationHash"), 463 activity_hash=payload.get("activityHash"), 464 ) 465 466 def deserialize_records( 467 self, 468 payload: typedefs.JSONObject, 469 scores: typing.Optional[records.RecordScores] = None, 470 **nodes: int, 471 ) -> records.Record: 472 objectives: typing.Optional[list[records.Objective]] = None 473 interval_objectives: typing.Optional[list[records.Objective]] = None 474 record_state: typedefs.IntAnd[records.RecordState] 475 476 record_state = records.RecordState(payload["state"]) 477 478 if raw_objs := payload.get("objectives"): 479 objectives = [self.deserialize_objectives(obj) for obj in raw_objs] 480 481 if raw_interval_objs := payload.get("intervalObjectives"): 482 interval_objectives = [ 483 self.deserialize_objectives(obj) for obj in raw_interval_objs 484 ] 485 486 return records.Record( 487 scores=scores, 488 categories_node_hash=nodes.get("categories_hash", undefined.UNDEFINED), 489 seals_node_hash=nodes.get("seals_hash", undefined.UNDEFINED), 490 state=record_state, 491 objectives=objectives, 492 interval_objectives=interval_objectives, 493 redeemed_count=payload.get("intervalsRedeemedCount", 0), 494 completion_times=payload.get("completedCount", None), 495 reward_visibility=payload.get("rewardVisibility"), 496 ) 497 498 def deserialize_character_records( 499 self, 500 payload: typedefs.JSONObject, 501 scores: typing.Optional[records.RecordScores] = None, 502 record_hashes: typing.Optional[list[int]] = None, 503 ) -> records.CharacterRecord: 504 record = self.deserialize_records(payload, scores) 505 return records.CharacterRecord( 506 scores=scores, 507 categories_node_hash=record.categories_node_hash, 508 seals_node_hash=record.seals_node_hash, 509 state=record.state, 510 objectives=record.objectives, 511 interval_objectives=record.interval_objectives, 512 redeemed_count=payload.get("intervalsRedeemedCount", 0), 513 completion_times=payload.get("completedCount"), 514 reward_visibility=payload.get("rewardVisibility"), 515 record_hashes=record_hashes or [], 516 ) 517 518 def deserialize_character_dye(self, payload: typedefs.JSONObject) -> character.Dye: 519 return character.Dye( 520 channel_hash=payload["channelHash"], dye_hash=payload["dyeHash"] 521 ) 522 523 def deserialize_character_customization( 524 self, payload: typedefs.JSONObject 525 ) -> character.CustomizationOptions: 526 return character.CustomizationOptions( 527 personality=payload["personality"], 528 face=payload["face"], 529 skin_color=payload["skinColor"], 530 lip_color=payload["lipColor"], 531 eye_color=payload["eyeColor"], 532 hair_colors=payload.get("hairColors", []), 533 feature_colors=payload.get("featureColors", []), 534 decal_color=payload["decalColor"], 535 wear_helmet=payload["wearHelmet"], 536 hair_index=payload["hairIndex"], 537 feature_index=payload["featureIndex"], 538 decal_index=payload["decalIndex"], 539 ) 540 541 def deserialize_character_minimal_equipments( 542 self, payload: typedefs.JSONObject 543 ) -> character.MinimalEquipments: 544 dyes = None 545 if raw_dyes := payload.get("dyes"): 546 if raw_dyes: 547 dyes = [self.deserialize_character_dye(dye) for dye in raw_dyes] 548 return character.MinimalEquipments( 549 net=self._net, item_hash=payload["itemHash"], dyes=dyes 550 ) 551 552 def deserialize_character_render_data( 553 self, payload: typedefs.JSONObject, / 554 ) -> character.RenderedData: 555 return character.RenderedData( 556 net=self._net, 557 customization=self.deserialize_character_customization( 558 payload["customization"] 559 ), 560 custom_dyes=[ 561 self.deserialize_character_dye(dye) 562 for dye in payload["customDyes"] 563 if dye 564 ], 565 equipment=[ 566 self.deserialize_character_minimal_equipments(equipment) 567 for equipment in payload["peerView"]["equipment"] 568 ], 569 ) 570 571 def deserialize_available_activity( 572 self, payload: typedefs.JSONObject 573 ) -> activity.AvailableActivity: 574 return activity.AvailableActivity( 575 hash=payload["activityHash"], 576 is_new=payload["isNew"], 577 is_completed=payload["isCompleted"], 578 is_visible=payload["isVisible"], 579 display_level=payload.get("displayLevel"), 580 recommended_light=payload.get("recommendedLight"), 581 difficulty=activity.Difficulty(payload["difficultyTier"]), 582 can_join=payload["canJoin"], 583 can_lead=payload["canLead"], 584 ) 585 586 def deserialize_character_activity( 587 self, payload: typedefs.JSONObject 588 ) -> activity.CharacterActivity: 589 current_mode: typing.Optional[enums.GameMode] = None 590 if raw_current_mode := payload.get("currentActivityModeType"): 591 current_mode = enums.GameMode(raw_current_mode) 592 593 current_mode_types: typing.Optional[collections.Sequence[enums.GameMode]] = None 594 if raw_current_modes := payload.get("currentActivityModeTypes"): 595 current_mode_types = [enums.GameMode(type_) for type_ in raw_current_modes] 596 597 return activity.CharacterActivity( 598 date_started=time.clean_date(payload["dateActivityStarted"]), 599 current_hash=payload["currentActivityHash"], 600 current_mode_hash=payload["currentActivityModeHash"], 601 current_mode=current_mode, 602 current_mode_hashes=payload.get("currentActivityModeHashes"), 603 current_mode_types=current_mode_types, 604 current_playlist_hash=payload.get("currentPlaylistActivityHash"), 605 last_story_hash=payload["lastCompletedStoryHash"], 606 available_activities=[ 607 self.deserialize_available_activity(activity_) 608 for activity_ in payload["availableActivities"] 609 ], 610 ) 611 612 def deserialize_profile_items( 613 self, payload: typedefs.JSONObject, / 614 ) -> list[profile.ProfileItemImpl]: 615 return [self.deserialize_profile_item(item) for item in payload["items"]] 616 617 def _deserialize_node(self, payload: typedefs.JSONObject) -> records.Node: 618 return records.Node( 619 state=int(payload["state"]), 620 objective=self.deserialize_objectives(payload["objective"]) 621 if "objective" in payload 622 else None, 623 progress_value=int(payload["progressValue"]), 624 completion_value=int(payload["completionValue"]), 625 record_category_score=int(payload["recordCategoryScore"]) 626 if "recordCategoryScore" in payload 627 else None, 628 ) 629 630 @staticmethod 631 def _deserialize_collectible(payload: typedefs.JSONObject) -> items.Collectible: 632 recent_collectibles: typing.Optional[collections.Collection[int]] = None 633 if raw_recent_collectibles := payload.get("recentCollectibleHashes"): 634 recent_collectibles = [ 635 int(item_hash) for item_hash in raw_recent_collectibles 636 ] 637 638 collectibles: dict[int, int] = {} 639 for item_hash, mapping in payload["collectibles"].items(): 640 collectibles[int(item_hash)] = int(mapping["state"]) 641 642 return items.Collectible( 643 recent_collectibles=recent_collectibles, 644 collectibles=collectibles, 645 collection_category_hash=int(payload["collectionCategoriesRootNodeHash"]), 646 collection_badges_hash=int(payload["collectionBadgesRootNodeHash"]), 647 ) 648 649 @staticmethod 650 def _deserialize_currencies( 651 payload: typedefs.JSONObject, 652 ) -> collections.Sequence[items.Currency]: 653 return [ 654 items.Currency(hash=int(item_hash), amount=int(amount)) 655 for item_hash, amount in payload["itemQuantities"].items() 656 ] 657 658 def deserialize_progressions( 659 self, payload: typedefs.JSONObject 660 ) -> progressions.Progression: 661 return progressions.Progression( 662 hash=int(payload["progressionHash"]), 663 level=int(payload["level"]), 664 cap=int(payload["levelCap"]), 665 daily_limit=int(payload["dailyLimit"]), 666 weekly_limit=int(payload["weeklyLimit"]), 667 current_progress=int(payload["currentProgress"]), 668 daily_progress=int(payload["dailyProgress"]), 669 needed=int(payload["progressToNextLevel"]), 670 next_level=int(payload["nextLevelAt"]), 671 ) 672 673 def _deserialize_factions( 674 self, payload: typedefs.JSONObject 675 ) -> progressions.Factions: 676 progs = self.deserialize_progressions(payload) 677 return progressions.Factions( 678 hash=progs.hash, 679 level=progs.level, 680 cap=progs.cap, 681 daily_limit=progs.daily_limit, 682 weekly_limit=progs.weekly_limit, 683 current_progress=progs.current_progress, 684 daily_progress=progs.daily_progress, 685 needed=progs.needed, 686 next_level=progs.next_level, 687 faction_hash=payload["factionHash"], 688 faction_vendor_hash=payload["factionVendorIndex"], 689 ) 690 691 def _deserialize_milestone_available_quest( 692 self, payload: typedefs.JSONObject 693 ) -> milestones.MilestoneQuest: 694 return milestones.MilestoneQuest( 695 item_hash=payload["questItemHash"], 696 status=self._deserialize_milestone_quest_status(payload["status"]), 697 ) 698 699 def _deserialize_milestone_activity( 700 self, payload: typedefs.JSONObject 701 ) -> milestones.MilestoneActivity: 702 phases: typing.Optional[ 703 collections.Sequence[milestones.MilestoneActivityPhase] 704 ] = None 705 if raw_phases := payload.get("phases"): 706 phases = [ 707 milestones.MilestoneActivityPhase( 708 is_completed=obj["complete"], hash=obj["phaseHash"] 709 ) 710 for obj in raw_phases 711 ] 712 713 return milestones.MilestoneActivity( 714 hash=payload["activityHash"], 715 challenges=[ 716 self.deserialize_objectives(obj["objective"]) 717 for obj in payload["challenges"] 718 ], 719 modifier_hashes=payload.get("modifierHashes"), 720 boolean_options=payload.get("booleanActivityOptions"), 721 phases=phases, 722 ) 723 724 def _deserialize_milestone_quest_status( 725 self, payload: typedefs.JSONObject 726 ) -> milestones.QuestStatus: 727 return milestones.QuestStatus( 728 net=self._net, 729 quest_hash=payload["questHash"], 730 step_hash=payload["stepHash"], 731 step_objectives=[ 732 self.deserialize_objectives(objective) 733 for objective in payload["stepObjectives"] 734 ], 735 is_tracked=payload["tracked"], 736 is_completed=payload["completed"], 737 started=payload["started"], 738 item_instance_id=payload["itemInstanceId"], 739 vendor_hash=payload.get("vendorHash"), 740 is_redeemed=payload["redeemed"], 741 ) 742 743 def _deserialize_milestone_rewards( 744 self, payload: typedefs.JSONObject 745 ) -> milestones.MilestoneReward: 746 return milestones.MilestoneReward( 747 category_hash=payload["rewardCategoryHash"], 748 entries=[ 749 milestones.MilestoneRewardEntry( 750 entry_hash=entry["rewardEntryHash"], 751 is_earned=entry["earned"], 752 is_redeemed=entry["redeemed"], 753 ) 754 for entry in payload["entries"] 755 ], 756 ) 757 758 def deserialize_milestone( 759 self, payload: typedefs.JSONObject 760 ) -> milestones.Milestone: 761 start_date: typing.Optional[datetime.datetime] = None 762 if raw_start_date := payload.get("startDate"): 763 start_date = time.clean_date(raw_start_date) 764 765 end_date: typing.Optional[datetime.datetime] = None 766 if raw_end_date := payload.get("endDate"): 767 end_date = time.clean_date(raw_end_date) 768 769 rewards: typing.Optional[ 770 collections.Collection[milestones.MilestoneReward] 771 ] = None 772 if raw_rewards := payload.get("rewards"): 773 rewards = [ 774 self._deserialize_milestone_rewards(reward) for reward in raw_rewards 775 ] 776 777 activities: typing.Optional[ 778 collections.Sequence[milestones.MilestoneActivity] 779 ] = None 780 if raw_activities := payload.get("activities"): 781 activities = [ 782 self._deserialize_milestone_activity(active) 783 for active in raw_activities 784 ] 785 786 quests: typing.Optional[collections.Sequence[milestones.MilestoneQuest]] = None 787 if raw_quests := payload.get("availableQuests"): 788 quests = [ 789 self._deserialize_milestone_available_quest(quest) 790 for quest in raw_quests 791 ] 792 793 vendors: typing.Optional[ 794 collections.Sequence[milestones.MilestoneVendor] 795 ] = None 796 if raw_vendors := payload.get("vendors"): 797 vendors = [ 798 milestones.MilestoneVendor( 799 vendor_hash=vendor["vendorHash"], 800 preview_itemhash=vendor.get("previewItemHash"), 801 ) 802 for vendor in raw_vendors 803 ] 804 805 return milestones.Milestone( 806 hash=payload["milestoneHash"], 807 start_date=start_date, 808 end_date=end_date, 809 order=payload["order"], 810 rewards=rewards, 811 available_quests=quests, 812 activities=activities, 813 vendors=vendors, 814 ) 815 816 def _deserialize_artifact_tiers( 817 self, payload: typedefs.JSONObject 818 ) -> season.ArtifactTier: 819 return season.ArtifactTier( 820 hash=payload["tierHash"], 821 is_unlocked=payload["isUnlocked"], 822 points_to_unlock=payload["pointsToUnlock"], 823 items=[ 824 season.ArtifactTierItem( 825 hash=item["itemHash"], is_active=item["isActive"] 826 ) 827 for item in payload["items"] 828 ], 829 ) 830 831 def deserialize_characters( 832 self, payload: typedefs.JSONObject 833 ) -> collections.Mapping[int, character.Character]: 834 return { 835 int(char_id): self._set_character_attrs(char) 836 for char_id, char in payload["data"].items() 837 } 838 839 def deserialize_character( 840 self, payload: typedefs.JSONObject 841 ) -> character.Character: 842 return self._set_character_attrs(payload) 843 844 def deserialize_character_equipments( 845 self, payload: typedefs.JSONObject 846 ) -> collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]: 847 return { 848 int(char_id): self.deserialize_profile_items(item) 849 for char_id, item in payload["data"].items() 850 } 851 852 def deserialize_character_activities( 853 self, payload: typedefs.JSONObject 854 ) -> collections.Mapping[int, activity.CharacterActivity]: 855 return { 856 int(char_id): self.deserialize_character_activity(data) 857 for char_id, data in payload["data"].items() 858 } 859 860 def deserialize_characters_render_data( 861 self, payload: typedefs.JSONObject 862 ) -> collections.Mapping[int, character.RenderedData]: 863 return { 864 int(char_id): self.deserialize_character_render_data(data) 865 for char_id, data in payload["data"].items() 866 } 867 868 def deserialize_character_progressions( 869 self, payload: typedefs.JSONObject 870 ) -> character.CharacterProgression: 871 progressions_ = { 872 int(prog_id): self.deserialize_progressions(prog) 873 for prog_id, prog in payload["progressions"].items() 874 } 875 876 factions = { 877 int(faction_id): self._deserialize_factions(faction) 878 for faction_id, faction in payload["factions"].items() 879 } 880 881 milestones_ = { 882 int(milestone_hash): self.deserialize_milestone(milestone) 883 for milestone_hash, milestone in payload["milestones"].items() 884 } 885 886 uninstanced_item_objectives = { 887 int(item_hash): [self.deserialize_objectives(ins) for ins in obj] 888 for item_hash, obj in payload["uninstancedItemObjectives"].items() 889 } 890 891 artifact = payload["seasonalArtifact"] 892 seasonal_artifact = season.CharacterScopedArtifact( 893 hash=artifact["artifactHash"], 894 points_used=artifact["pointsUsed"], 895 reset_count=artifact["resetCount"], 896 tiers=[ 897 self._deserialize_artifact_tiers(tier) for tier in artifact["tiers"] 898 ], 899 ) 900 checklists = payload["checklists"] 901 902 return character.CharacterProgression( 903 progressions=progressions_, 904 factions=factions, 905 checklists=checklists, 906 milestones=milestones_, 907 seasonal_artifact=seasonal_artifact, 908 uninstanced_item_objectives=uninstanced_item_objectives, 909 ) 910 911 def deserialize_character_progressions_mapping( 912 self, payload: typedefs.JSONObject 913 ) -> collections.Mapping[int, character.CharacterProgression]: 914 character_progressions: collections.Mapping[ 915 int, character.CharacterProgression 916 ] = {} 917 for char_id, data in payload["data"].items(): 918 # A little hack to stop mypy complaining about Mapping <-> dict 919 character_progressions[ 920 int(char_id) 921 ] = self.deserialize_character_progressions(data) # type: ignore[index] 922 return character_progressions 923 924 def deserialize_characters_records( 925 self, 926 payload: typedefs.JSONObject, 927 ) -> collections.Mapping[int, records.CharacterRecord]: 928 return { 929 int(rec_id): self.deserialize_character_records( 930 rec, record_hashes=payload.get("featuredRecordHashes") 931 ) 932 for rec_id, rec in payload["records"].items() 933 } 934 935 def deserialize_profile_records( 936 self, payload: typedefs.JSONObject 937 ) -> collections.Mapping[int, records.Record]: 938 raw_profile_records = payload["data"] 939 scores = records.RecordScores( 940 current_score=raw_profile_records["score"], 941 legacy_score=raw_profile_records["legacyScore"], 942 lifetime_score=raw_profile_records["lifetimeScore"], 943 ) 944 return { 945 int(record_id): self.deserialize_records( 946 record, 947 scores, 948 categories_hash=raw_profile_records["recordCategoriesRootNodeHash"], 949 seals_hash=raw_profile_records["recordSealsRootNodeHash"], 950 ) 951 for record_id, record in raw_profile_records["records"].items() 952 } 953 954 def _deserialize_craftable_socket_plug( 955 self, payload: typedefs.JSONObject 956 ) -> items.CraftableSocketPlug: 957 return items.CraftableSocketPlug( 958 item_hash=int(payload["plugItemHash"]), 959 failed_requirement_indexes=payload.get("failedRequirementIndexes", []), 960 ) 961 962 def _deserialize_craftable_socket( 963 self, payload: typedefs.JSONObject 964 ) -> items.CraftableSocket: 965 plugs: list[items.CraftableSocketPlug] = [] 966 if raw_plug := payload.get("plug"): 967 plugs.extend( 968 self._deserialize_craftable_socket_plug(plug) for plug in raw_plug 969 ) 970 971 return items.CraftableSocket( 972 plug_set_hash=int(payload["plugSetHash"]), plugs=plugs 973 ) 974 975 def _deserialize_craftable_item( 976 self, payload: typedefs.JSONObject 977 ) -> items.CraftableItem: 978 return items.CraftableItem( 979 is_visible=payload["visible"], 980 failed_requirement_indexes=payload.get("failedRequirementIndexes", []), 981 sockets=[ 982 self._deserialize_craftable_socket(socket) 983 for socket in payload["sockets"] 984 ], 985 ) 986 987 def deserialize_craftables_component( 988 self, payload: typedefs.JSONObject 989 ) -> components.CraftablesComponent: 990 return components.CraftablesComponent( 991 net=self._net, 992 craftables={ 993 int(item_id): self._deserialize_craftable_item(item) 994 for item_id, item in payload["craftables"].items() 995 if item is not None 996 }, 997 crafting_root_node_hash=payload["craftingRootNodeHash"], 998 ) 999 1000 def deserialize_components( # noqa: C901 Too complex. 1001 self, payload: typedefs.JSONObject 1002 ) -> components.Component: 1003 profile_: typing.Optional[profile.Profile] = None 1004 if raw_profile := payload.get("profile"): 1005 profile_ = self.deserialize_profile(raw_profile) 1006 1007 profile_progression: typing.Optional[profile.ProfileProgression] = None 1008 if raw_profile_progression := payload.get("profileProgression"): 1009 profile_progression = self.deserialize_profile_progression( 1010 raw_profile_progression 1011 ) 1012 1013 profile_currencies: typing.Optional[ 1014 collections.Sequence[profile.ProfileItemImpl] 1015 ] = None 1016 if raw_profile_currencies := payload.get("profileCurrencies"): 1017 if "data" in raw_profile_currencies: 1018 profile_currencies = self.deserialize_profile_items( 1019 raw_profile_currencies["data"] 1020 ) 1021 1022 profile_inventories: typing.Optional[ 1023 collections.Sequence[profile.ProfileItemImpl] 1024 ] = None 1025 if raw_profile_inventories := payload.get("profileInventory"): 1026 if "data" in raw_profile_inventories: 1027 profile_inventories = self.deserialize_profile_items( 1028 raw_profile_inventories["data"] 1029 ) 1030 1031 profile_records: typing.Optional[ 1032 collections.Mapping[int, records.Record] 1033 ] = None 1034 1035 if raw_profile_records_ := payload.get("profileRecords"): 1036 profile_records = self.deserialize_profile_records(raw_profile_records_) 1037 1038 characters: typing.Optional[typing.Mapping[int, character.Character]] = None 1039 if raw_characters := payload.get("characters"): 1040 characters = self.deserialize_characters(raw_characters) 1041 1042 character_records: typing.Optional[ 1043 collections.Mapping[int, records.CharacterRecord] 1044 ] = None 1045 1046 if raw_character_records := payload.get("characterRecords"): 1047 # Had to do it in two steps.. 1048 to_update: typedefs.JSONObject = {} 1049 for _, data in raw_character_records["data"].items(): 1050 for record_id, record in data.items(): 1051 to_update[record_id] = record 1052 1053 character_records = { 1054 int(rec_id): self.deserialize_character_records( 1055 rec, record_hashes=to_update.get("featuredRecordHashes") 1056 ) 1057 for rec_id, rec in to_update["records"].items() 1058 } 1059 1060 character_equipments: typing.Optional[ 1061 collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]] 1062 ] = None 1063 if raw_character_equips := payload.get("characterEquipment"): 1064 character_equipments = self.deserialize_character_equipments( 1065 raw_character_equips 1066 ) 1067 1068 character_inventories: typing.Optional[ 1069 collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]] 1070 ] = None 1071 if raw_character_inventories := payload.get("characterInventories"): 1072 if "data" in raw_character_inventories: 1073 character_inventories = self.deserialize_character_equipments( 1074 raw_character_inventories 1075 ) 1076 1077 character_activities: typing.Optional[ 1078 collections.Mapping[int, activity.CharacterActivity] 1079 ] = None 1080 if raw_char_acts := payload.get("characterActivities"): 1081 character_activities = self.deserialize_character_activities(raw_char_acts) 1082 1083 character_render_data: typing.Optional[ 1084 collections.Mapping[int, character.RenderedData] 1085 ] = None 1086 if raw_character_render_data := payload.get("characterRenderData"): 1087 character_render_data = self.deserialize_characters_render_data( 1088 raw_character_render_data 1089 ) 1090 1091 character_progressions: typing.Optional[ 1092 collections.Mapping[int, character.CharacterProgression] 1093 ] = None 1094 1095 if raw_character_progressions := payload.get("characterProgressions"): 1096 character_progressions = self.deserialize_character_progressions_mapping( 1097 raw_character_progressions 1098 ) 1099 1100 profile_string_vars: typing.Optional[collections.Mapping[int, int]] = None 1101 if raw_profile_string_vars := payload.get("profileStringVariables"): 1102 profile_string_vars = raw_profile_string_vars["data"]["integerValuesByHash"] 1103 1104 character_string_vars: typing.Optional[ 1105 collections.Mapping[int, collections.Mapping[int, int]] 1106 ] = None 1107 if raw_character_string_vars := payload.get("characterStringVariables"): 1108 character_string_vars = { 1109 int(char_id): data["integerValuesByHash"] 1110 for char_id, data in raw_character_string_vars["data"].items() 1111 } 1112 1113 metrics: typing.Optional[ 1114 collections.Sequence[ 1115 collections.Mapping[ 1116 int, tuple[bool, typing.Optional[records.Objective]] 1117 ] 1118 ] 1119 ] = None 1120 root_node_hash: typing.Optional[int] = None 1121 1122 if raw_metrics := payload.get("metrics"): 1123 root_node_hash = raw_metrics["data"]["metricsRootNodeHash"] 1124 metrics = [ 1125 { 1126 int(metrics_hash): ( 1127 data["invisible"], 1128 self.deserialize_objectives(data["objectiveProgress"]) 1129 if "objectiveProgress" in data 1130 else None, 1131 ) 1132 for metrics_hash, data in raw_metrics["data"]["metrics"].items() 1133 } 1134 ] 1135 transitory: typing.Optional[fireteams.FireteamParty] = None 1136 if raw_transitory := payload.get("profileTransitoryData"): 1137 if "data" in raw_transitory: 1138 transitory = self.deserialize_fireteam_party(raw_transitory["data"]) 1139 1140 item_components: typing.Optional[components.ItemsComponent] = None 1141 if raw_item_components := payload.get("itemComponents"): 1142 item_components = self.deserialize_items_component(raw_item_components) 1143 1144 profile_plugsets: typing.Optional[ 1145 collections.Mapping[int, collections.Sequence[items.PlugItemState]] 1146 ] = None 1147 1148 if raw_profile_plugs := payload.get("profilePlugSets"): 1149 profile_plugsets = { 1150 int(index): [self.deserialize_plug_item_state(state) for state in data] 1151 for index, data in raw_profile_plugs["data"]["plugs"].items() 1152 } 1153 1154 character_plugsets: typing.Optional[ 1155 collections.Mapping[ 1156 int, collections.Mapping[int, collections.Sequence[items.PlugItemState]] 1157 ] 1158 ] = None 1159 if raw_char_plugsets := payload.get("characterPlugSets"): 1160 character_plugsets = { 1161 int(char_id): { 1162 int(index): [ 1163 self.deserialize_plug_item_state(state) for state in data 1164 ] 1165 for index, data in inner["plugs"].items() 1166 } 1167 for char_id, inner in raw_char_plugsets["data"].items() 1168 } 1169 1170 character_collectibles: typing.Optional[ 1171 collections.Mapping[int, items.Collectible] 1172 ] = None 1173 if raw_character_collectibles := payload.get("characterCollectibles"): 1174 character_collectibles = { 1175 int(char_id): self._deserialize_collectible(data) 1176 for char_id, data in raw_character_collectibles["data"].items() 1177 } 1178 1179 profile_collectibles: typing.Optional[items.Collectible] = None 1180 if raw_profile_collectibles := payload.get("profileCollectibles"): 1181 profile_collectibles = self._deserialize_collectible( 1182 raw_profile_collectibles["data"] 1183 ) 1184 1185 profile_nodes: typing.Optional[collections.Mapping[int, records.Node]] = None 1186 if raw_profile_nodes := payload.get("profilePresentationNodes"): 1187 profile_nodes = { 1188 int(node_hash): self._deserialize_node(node) 1189 for node_hash, node in raw_profile_nodes["data"]["nodes"].items() 1190 } 1191 1192 character_nodes: typing.Optional[ 1193 collections.Mapping[int, collections.Mapping[int, records.Node]] 1194 ] = None 1195 if raw_character_nodes := payload.get("characterPresentationNodes"): 1196 character_nodes = { 1197 int(char_id): { 1198 int(node_hash): self._deserialize_node(node) 1199 for node_hash, node in each_character["nodes"].items() 1200 } 1201 for char_id, each_character in raw_character_nodes["data"].items() 1202 } 1203 1204 platform_silver: typing.Optional[ 1205 collections.Mapping[str, profile.ProfileItemImpl] 1206 ] = None 1207 if raw_platform_silver := payload.get("platformSilver"): 1208 if "data" in raw_platform_silver: 1209 platform_silver = { 1210 platform_name: self.deserialize_profile_item(item) 1211 for platform_name, item in raw_platform_silver["data"][ 1212 "platformSilver" 1213 ].items() 1214 } 1215 1216 character_currency_lookups: typing.Optional[ 1217 collections.Mapping[int, collections.Sequence[items.Currency]] 1218 ] = None 1219 if raw_char_lookups := payload.get("characterCurrencyLookups"): 1220 if "data" in raw_char_lookups: 1221 character_currency_lookups = { 1222 int(char_id): self._deserialize_currencies(currency) 1223 for char_id, currency in raw_char_lookups["data"].items() 1224 } 1225 1226 character_craftables: typing.Optional[ 1227 collections.Mapping[int, components.CraftablesComponent] 1228 ] = None 1229 if raw_character_craftables := payload.get("characterCraftables"): 1230 if "data" in raw_character_craftables: 1231 character_craftables = { 1232 int(char_id): self.deserialize_craftables_component(craftable) 1233 for char_id, craftable in raw_character_craftables["data"].items() 1234 } 1235 1236 return components.Component( 1237 profiles=profile_, 1238 profile_progression=profile_progression, 1239 profile_currencies=profile_currencies, 1240 profile_inventories=profile_inventories, 1241 profile_records=profile_records, 1242 characters=characters, 1243 character_records=character_records, 1244 character_equipments=character_equipments, 1245 character_inventories=character_inventories, 1246 character_activities=character_activities, 1247 character_render_data=character_render_data, 1248 character_progressions=character_progressions, 1249 profile_string_variables=profile_string_vars, 1250 character_string_variables=character_string_vars, 1251 metrics=metrics, 1252 root_node_hash=root_node_hash, 1253 transitory=transitory, 1254 item_components=item_components, 1255 profile_plugsets=profile_plugsets, 1256 character_plugsets=character_plugsets, 1257 character_collectibles=character_collectibles, 1258 profile_collectibles=profile_collectibles, 1259 profile_nodes=profile_nodes, 1260 character_nodes=character_nodes, 1261 platform_silver=platform_silver, 1262 character_currency_lookups=character_currency_lookups, 1263 character_craftables=character_craftables, 1264 ) 1265 1266 def deserialize_items_component( 1267 self, payload: typedefs.JSONObject 1268 ) -> components.ItemsComponent: 1269 instances: typing.Optional[ 1270 collections.Sequence[collections.Mapping[int, items.ItemInstance]] 1271 ] = None 1272 if raw_instances := payload.get("instances"): 1273 instances = [ 1274 { 1275 int(ins_id): self.deserialize_instanced_item(item) 1276 for ins_id, item in raw_instances["data"].items() 1277 } 1278 ] 1279 1280 render_data: typing.Optional[ 1281 collections.Mapping[int, tuple[bool, dict[int, int]]] 1282 ] = None 1283 if raw_render_data := payload.get("renderData"): 1284 render_data = { 1285 int(ins_id): (data["useCustomDyes"], data["artRegions"]) 1286 for ins_id, data in raw_render_data["data"].items() 1287 } 1288 1289 stats: typing.Optional[collections.Mapping[int, items.ItemStatsView]] = None 1290 if raw_stats := payload.get("stats"): 1291 builder: collections.Mapping[int, items.ItemStatsView] = {} 1292 for ins_id, stat in raw_stats["data"].items(): 1293 for _, items_ in stat.items(): 1294 builder[int(ins_id)] = self.deserialize_item_stats_view(items_) # type: ignore[index] 1295 stats = builder 1296 1297 sockets: typing.Optional[ 1298 collections.Mapping[int, collections.Sequence[items.ItemSocket]] 1299 ] = None 1300 if raw_sockets := payload.get("sockets"): 1301 sockets = { 1302 int(ins_id): [ 1303 self.deserialize_item_socket(socket) for socket in item["sockets"] 1304 ] 1305 for ins_id, item in raw_sockets["data"].items() 1306 } 1307 1308 objectives: typing.Optional[ 1309 collections.Mapping[int, collections.Sequence[records.Objective]] 1310 ] = None 1311 if raw_objectives := payload.get("objectives"): 1312 objectives = { 1313 int(ins_id): [self.deserialize_objectives(objective)] 1314 for ins_id, data in raw_objectives["data"].items() 1315 for objective in data["objectives"] 1316 } 1317 1318 perks: typing.Optional[ 1319 collections.Mapping[int, collections.Collection[items.ItemPerk]] 1320 ] = None 1321 if raw_perks := payload.get("perks"): 1322 perks = { 1323 int(ins_id): [ 1324 self.deserialize_item_perk(perk) for perk in item["perks"] 1325 ] 1326 for ins_id, item in raw_perks["data"].items() 1327 } 1328 1329 plug_states: typing.Optional[collections.Sequence[items.PlugItemState]] = None 1330 if raw_plug_states := payload.get("plugStates"): 1331 pending_states: list[items.PlugItemState] = [] 1332 for _, plug in raw_plug_states["data"].items(): 1333 pending_states.append(self.deserialize_plug_item_state(plug)) 1334 plug_states = pending_states 1335 1336 reusable_plugs: typing.Optional[ 1337 collections.Mapping[int, collections.Sequence[items.PlugItemState]] 1338 ] = None 1339 if raw_re_plugs := payload.get("reusablePlugs"): 1340 reusable_plugs = { 1341 int(ins_id): [ 1342 self.deserialize_plug_item_state(state) for state in inner 1343 ] 1344 for ins_id, plug in raw_re_plugs["data"].items() 1345 for inner in list(plug["plugs"].values()) 1346 } 1347 1348 plug_objectives: typing.Optional[ 1349 collections.Mapping[ 1350 int, collections.Mapping[int, collections.Collection[records.Objective]] 1351 ] 1352 ] = None 1353 if raw_plug_objectives := payload.get("plugObjectives"): 1354 plug_objectives = { 1355 int(ins_id): { 1356 int(obj_hash): [self.deserialize_objectives(obj) for obj in objs] 1357 for obj_hash, objs in inner["objectivesPerPlug"].items() 1358 } 1359 for ins_id, inner in raw_plug_objectives["data"].items() 1360 } 1361 1362 return components.ItemsComponent( 1363 sockets=sockets, 1364 stats=stats, 1365 render_data=render_data, 1366 instances=instances, 1367 objectives=objectives, 1368 perks=perks, 1369 plug_states=plug_states, 1370 reusable_plugs=reusable_plugs, 1371 plug_objectives=plug_objectives, 1372 ) 1373 1374 def deserialize_character_component( # type: ignore[call-arg] 1375 self, payload: typedefs.JSONObject 1376 ) -> components.CharacterComponent: 1377 character_: typing.Optional[character.Character] = None 1378 if raw_singular_character := payload.get("character"): 1379 character_ = self.deserialize_character(raw_singular_character["data"]) 1380 1381 inventory: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None 1382 if raw_inventory := payload.get("inventory"): 1383 if "data" in raw_inventory: 1384 inventory = self.deserialize_profile_items(raw_inventory["data"]) 1385 1386 activities: typing.Optional[activity.CharacterActivity] = None 1387 if raw_activities := payload.get("activities"): 1388 activities = self.deserialize_character_activity(raw_activities["data"]) 1389 1390 equipment: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None 1391 if raw_equipments := payload.get("equipment"): 1392 equipment = self.deserialize_profile_items(raw_equipments["data"]) 1393 1394 progressions_: typing.Optional[character.CharacterProgression] = None 1395 if raw_progressions := payload.get("progressions"): 1396 progressions_ = self.deserialize_character_progressions( 1397 raw_progressions["data"] 1398 ) 1399 1400 render_data: typing.Optional[character.RenderedData] = None 1401 if raw_render_data := payload.get("renderData"): 1402 render_data = self.deserialize_character_render_data( 1403 raw_render_data["data"] 1404 ) 1405 1406 character_records: typing.Optional[ 1407 collections.Mapping[int, records.CharacterRecord] 1408 ] = None 1409 if raw_char_records := payload.get("records"): 1410 character_records = self.deserialize_characters_records( 1411 raw_char_records["data"] 1412 ) 1413 1414 item_components: typing.Optional[components.ItemsComponent] = None 1415 if raw_item_components := payload.get("itemComponents"): 1416 item_components = self.deserialize_items_component(raw_item_components) 1417 1418 nodes: typing.Optional[collections.Mapping[int, records.Node]] = None 1419 if raw_nodes := payload.get("presentationNodes"): 1420 nodes = { 1421 int(node_hash): self._deserialize_node(node) 1422 for node_hash, node in raw_nodes["data"]["nodes"].items() 1423 } 1424 1425 collectibles: typing.Optional[items.Collectible] = None 1426 if raw_collectibles := payload.get("collectibles"): 1427 collectibles = self._deserialize_collectible(raw_collectibles["data"]) 1428 1429 currency_lookups: typing.Optional[collections.Sequence[items.Currency]] = None 1430 if raw_currencies := payload.get("currencyLookups"): 1431 if "data" in raw_currencies: 1432 currency_lookups = self._deserialize_currencies(raw_currencies) 1433 1434 return components.CharacterComponent( 1435 activities=activities, 1436 equipment=equipment, 1437 inventory=inventory, 1438 progressions=progressions_, 1439 render_data=render_data, 1440 character=character_, 1441 character_records=character_records, 1442 profile_records=None, 1443 item_components=item_components, 1444 currency_lookups=currency_lookups, 1445 collectibles=collectibles, 1446 nodes=nodes, 1447 ) 1448 1449 def _set_entity_attrs( 1450 self, payload: typedefs.JSONObject, *, key: str = "displayProperties" 1451 ) -> entity.Entity: 1452 name: undefined.UndefinedOr[str] = undefined.UNDEFINED 1453 description: undefined.UndefinedOr[str] = undefined.UNDEFINED 1454 1455 if properties := payload[key]: 1456 if (raw_name := properties["name"]) is not typedefs.Unknown: 1457 name = raw_name 1458 1459 if ( 1460 raw_description := properties["description"] 1461 ) and not typedefs.is_unknown(raw_description): 1462 description = raw_description 1463 1464 return entity.Entity( 1465 net=self._net, 1466 hash=payload["hash"], 1467 index=payload["index"], 1468 name=name, 1469 description=description, 1470 has_icon=properties["hasIcon"], 1471 icon=assets.Image(properties["icon"] if "icon" in properties else None), 1472 ) 1473 1474 def deserialize_inventory_results( 1475 self, payload: typedefs.JSONObject 1476 ) -> iterators.Iterator[entity.SearchableEntity]: 1477 suggested_words: list[str] = payload["suggestedWords"] 1478 1479 def _check_unknown(s: str) -> undefined.UndefinedOr[str]: 1480 return s if not typedefs.is_unknown(s) else undefined.UNDEFINED 1481 1482 return iterators.Iterator( 1483 [ 1484 entity.SearchableEntity( 1485 net=self._net, 1486 hash=data["hash"], 1487 entity_type=data["entityType"], 1488 weight=data["weight"], 1489 suggested_words=suggested_words, 1490 name=data["displayProperties"]["name"], 1491 has_icon=data["displayProperties"]["hasIcon"], 1492 description=_check_unknown( 1493 data["displayProperties"]["description"] 1494 ), 1495 icon=assets.Image(data["displayProperties"]["icon"]), 1496 ) 1497 for data in payload["results"]["results"] 1498 ] 1499 ) 1500 1501 def _deserialize_inventory_item_objects( 1502 self, payload: typedefs.JSONObject 1503 ) -> entity.InventoryEntityObjects: 1504 return entity.InventoryEntityObjects( 1505 action=payload.get("action"), 1506 set_data=payload.get("setData"), 1507 stats=payload.get("stats"), 1508 equipping_block=payload.get("equippingBlock"), 1509 translation_block=payload.get("translationBlock"), 1510 preview=payload.get("preview"), 1511 quality=payload.get("quality"), 1512 value=payload.get("value"), 1513 source_data=payload.get("sourceData"), 1514 objectives=payload.get("objectives"), 1515 plug=payload.get("plug"), 1516 metrics=payload.get("metrics"), 1517 gearset=payload.get("gearset"), 1518 sack=payload.get("sack"), 1519 sockets=payload.get("sockets"), 1520 summary=payload.get("summary"), 1521 talent_gird=payload.get("talentGrid"), 1522 investments_stats=payload.get("investmentStats"), 1523 perks=payload.get("perks"), 1524 animations=payload.get("animations", []), 1525 links=payload.get("links", []), 1526 ) 1527 1528 def deserialize_inventory_entity( # noqa: C901 Too complex. 1529 self, payload: typedefs.JSONObject, / 1530 ) -> entity.InventoryEntity: 1531 props = self._set_entity_attrs(payload) 1532 objects = self._deserialize_inventory_item_objects(payload) 1533 1534 collectible_hash: typing.Optional[int] = None 1535 if raw_collectible_hash := payload.get("collectibleHash"): 1536 collectible_hash = int(raw_collectible_hash) 1537 1538 secondary_icon: undefined.UndefinedOr[assets.Image] = undefined.UNDEFINED 1539 if raw_second_icon := payload.get("secondaryIcon"): 1540 secondary_icon = assets.Image(raw_second_icon) 1541 1542 secondary_overlay: undefined.UndefinedOr[assets.Image] = undefined.UNDEFINED 1543 if raw_second_overlay := payload.get("secondaryOverlay"): 1544 secondary_overlay = assets.Image(raw_second_overlay) 1545 1546 secondary_special: undefined.UndefinedOr[assets.Image] = undefined.UNDEFINED 1547 if raw_second_special := payload.get("secondarySpecial"): 1548 secondary_special = assets.Image(raw_second_special) 1549 1550 screenshot: undefined.UndefinedOr[assets.Image] = undefined.UNDEFINED 1551 if raw_screenshot := payload.get("screenshot"): 1552 screenshot = assets.Image(raw_screenshot) 1553 1554 watermark_icon: typing.Optional[assets.Image] = None 1555 if raw_watermark_icon := payload.get("iconWatermark"): 1556 watermark_icon = assets.Image(raw_watermark_icon) 1557 1558 watermark_shelved: typing.Optional[assets.Image] = None 1559 if raw_watermark_shelved := payload.get("iconWatermarkShelved"): 1560 watermark_shelved = assets.Image(raw_watermark_shelved) 1561 1562 about: undefined.UndefinedOr[str] = undefined.UNDEFINED 1563 if (raw_about := payload.get("flavorText")) and not typedefs.is_unknown( 1564 raw_about 1565 ): 1566 about = raw_about 1567 1568 ui_item_style: undefined.UndefinedOr[str] = undefined.UNDEFINED 1569 if ( 1570 raw_ui_style := payload.get("uiItemDisplayStyle") 1571 ) and not typedefs.is_unknown(raw_ui_style): 1572 ui_item_style = raw_ui_style 1573 1574 tier_and_name: undefined.UndefinedOr[str] = undefined.UNDEFINED 1575 if ( 1576 raw_tier_and_name := payload.get("itemTypeAndTierDisplayName") 1577 ) and not typedefs.is_unknown(raw_tier_and_name): 1578 tier_and_name = raw_tier_and_name 1579 1580 type_name: undefined.UndefinedOr[str] = undefined.UNDEFINED 1581 if ( 1582 raw_type_name := payload.get("itemTypeDisplayName") 1583 ) and not typedefs.is_unknown(raw_type_name): 1584 type_name = raw_type_name 1585 1586 display_source: undefined.UndefinedOr[str] = undefined.UNDEFINED 1587 if ( 1588 raw_display_source := payload.get("displaySource") 1589 ) and not typedefs.is_unknown(raw_display_source): 1590 display_source = raw_display_source 1591 1592 lorehash: typing.Optional[int] = None 1593 if raw_lore_hash := payload.get("loreHash"): 1594 lorehash = int(raw_lore_hash) 1595 1596 summary_hash: typing.Optional[int] = None 1597 if raw_summary_hash := payload.get("summaryItemHash"): 1598 summary_hash = raw_summary_hash 1599 1600 breaker_type_hash: typing.Optional[int] = None 1601 if raw_breaker_type_hash := payload.get("breakerTypeHash"): 1602 breaker_type_hash = int(raw_breaker_type_hash) 1603 1604 damage_types: typing.Optional[collections.Sequence[int]] = None 1605 if raw_damage_types := payload.get("damageTypes"): 1606 damage_types = [int(type_) for type_ in raw_damage_types] 1607 1608 damagetype_hashes: typing.Optional[collections.Sequence[int]] = None 1609 if raw_damagetype_hashes := payload.get("damageTypeHashes"): 1610 damagetype_hashes = [int(type_) for type_ in raw_damagetype_hashes] 1611 1612 default_damagetype_hash: typing.Optional[int] = None 1613 if raw_defaultdmg_hash := payload.get("defaultDamageTypeHash"): 1614 default_damagetype_hash = int(raw_defaultdmg_hash) 1615 1616 emblem_objective_hash: typing.Optional[int] = None 1617 if raw_emblem_obj_hash := payload.get("emblemObjectiveHash"): 1618 emblem_objective_hash = int(raw_emblem_obj_hash) 1619 1620 tier_type: typing.Optional[enums.TierType] = None 1621 tier: typing.Optional[enums.ItemTier] = None 1622 bucket_hash: typing.Optional[int] = None 1623 recovery_hash: typing.Optional[int] = None 1624 tier_name: undefined.UndefinedOr[str] = undefined.UNDEFINED 1625 isinstance_item: bool = False 1626 expire_tool_tip: undefined.UndefinedOr[str] = undefined.UNDEFINED 1627 expire_in_orbit_message: undefined.UndefinedOr[str] = undefined.UNDEFINED 1628 suppress_expiration: bool = False 1629 max_stack_size: typing.Optional[int] = None 1630 stack_label: undefined.UndefinedOr[str] = undefined.UNDEFINED 1631 1632 if inventory := payload.get("inventory"): 1633 tier_type = enums.TierType(int(inventory["tierType"])) 1634 tier = enums.ItemTier(int(inventory["tierTypeHash"])) 1635 bucket_hash = int(inventory["bucketTypeHash"]) 1636 recovery_hash = int(inventory["recoveryBucketTypeHash"]) 1637 tier_name = inventory["tierTypeName"] 1638 isinstance_item = inventory["isInstanceItem"] 1639 suppress_expiration = inventory["suppressExpirationWhenObjectivesComplete"] 1640 max_stack_size = int(inventory["maxStackSize"]) 1641 1642 try: 1643 stack_label = inventory["stackUniqueLabel"] 1644 except KeyError: 1645 pass 1646 1647 return entity.InventoryEntity( 1648 net=self._net, 1649 collectible_hash=collectible_hash, 1650 name=props.name, 1651 about=about, 1652 emblem_objective_hash=emblem_objective_hash, 1653 suppress_expiration=suppress_expiration, 1654 max_stack_size=max_stack_size, 1655 stack_label=stack_label, 1656 tier=tier, 1657 tier_type=tier_type, 1658 tier_name=tier_name, 1659 bucket_hash=bucket_hash, 1660 recovery_bucket_hash=recovery_hash, 1661 isinstance_item=isinstance_item, 1662 expire_in_orbit_message=expire_in_orbit_message, 1663 expiration_tooltip=expire_tool_tip, 1664 lore_hash=lorehash, 1665 type_and_tier_name=tier_and_name, 1666 summary_hash=summary_hash, 1667 ui_display_style=ui_item_style, 1668 type_name=type_name, 1669 breaker_type_hash=breaker_type_hash, 1670 description=props.description, 1671 display_source=display_source, 1672 hash=props.hash, 1673 damage_types=damage_types, 1674 index=props.index, 1675 icon=props.icon, 1676 has_icon=props.has_icon, 1677 screenshot=screenshot, 1678 watermark_icon=watermark_icon, 1679 watermark_shelved=watermark_shelved, 1680 secondary_icon=secondary_icon, 1681 secondary_overlay=secondary_overlay, 1682 secondary_special=secondary_special, 1683 type=enums.ItemType(int(payload["itemType"])), 1684 trait_hashes=[int(id_) for id_ in payload.get("traitHashes", [])], 1685 trait_ids=[trait for trait in payload.get("traitIds", [])], 1686 category_hashes=[int(hash_) for hash_ in payload["itemCategoryHashes"]], 1687 item_class=enums.Class(int(payload["classType"])), 1688 sub_type=enums.ItemSubType(int(payload["itemSubType"])), 1689 breaker_type=int(payload["breakerType"]), 1690 default_damagetype=int(payload["defaultDamageType"]), 1691 default_damagetype_hash=default_damagetype_hash, 1692 damagetype_hashes=damagetype_hashes, 1693 tooltip_notifications=payload["tooltipNotifications"], 1694 not_transferable=payload["nonTransferrable"], 1695 allow_actions=payload["allowActions"], 1696 is_equippable=payload["equippable"], 1697 objects=objects, 1698 background_colors=payload.get("backgroundColor", {}), 1699 season_hash=payload.get("seasonHash"), 1700 has_postmaster_effect=payload["doesPostmasterPullHaveSideEffects"], 1701 ) 1702 1703 def deserialize_objective_entity( 1704 self, payload: typedefs.JSONObject, / 1705 ) -> entity.ObjectiveEntity: 1706 props = self._set_entity_attrs(payload) 1707 return entity.ObjectiveEntity( 1708 net=self._net, 1709 hash=props.hash, 1710 index=props.index, 1711 description=props.description, 1712 name=props.name, 1713 has_icon=props.has_icon, 1714 icon=props.icon, 1715 unlock_value_hash=payload["unlockValueHash"], 1716 completion_value=payload["completionValue"], 1717 scope=entity.GatingScope(int(payload["scope"])), 1718 location_hash=payload["locationHash"], 1719 allowed_negative_value=payload["allowNegativeValue"], 1720 allowed_value_change=payload["allowValueChangeWhenCompleted"], 1721 counting_downward=payload["isCountingDownward"], 1722 value_style=entity.ValueUIStyle(int(payload["valueStyle"])), 1723 progress_description=payload["progressDescription"], 1724 perks=payload["perks"], 1725 stats=payload["stats"], 1726 minimum_visibility=payload["minimumVisibilityThreshold"], 1727 allow_over_completion=payload["allowOvercompletion"], 1728 show_value_style=payload["showValueOnComplete"], 1729 display_only_objective=payload["isDisplayOnlyObjective"], 1730 complete_value_style=entity.ValueUIStyle( 1731 int(payload["completedValueStyle"]) 1732 ), 1733 progress_value_style=entity.ValueUIStyle( 1734 int(payload["inProgressValueStyle"]) 1735 ), 1736 ui_label=payload["uiLabel"], 1737 ui_style=entity.ObjectiveUIStyle(int(payload["uiStyle"])), 1738 ) 1739 1740 def _deserialize_activity_values( 1741 self, payload: typedefs.JSONObject, / 1742 ) -> activity.ActivityValues: 1743 team: typing.Optional[int] = None 1744 if raw_team := payload.get("team"): 1745 team = raw_team["basic"]["value"] 1746 return activity.ActivityValues( 1747 assists=payload["assists"]["basic"]["value"], 1748 deaths=payload["deaths"]["basic"]["value"], 1749 kills=payload["kills"]["basic"]["value"], 1750 is_completed=bool(payload["completed"]["basic"]["value"]), 1751 opponents_defeated=payload["opponentsDefeated"]["basic"]["value"], 1752 efficiency=payload["efficiency"]["basic"]["value"], 1753 kd_ratio=payload["killsDeathsRatio"]["basic"]["value"], 1754 kd_assists=payload["killsDeathsAssists"]["basic"]["value"], 1755 score=payload["score"]["basic"]["value"], 1756 duration=payload["activityDurationSeconds"]["basic"]["displayValue"], 1757 team=team, 1758 completion_reason=payload["completionReason"]["basic"]["displayValue"], 1759 fireteam_id=payload["fireteamId"]["basic"]["value"], 1760 start_seconds=payload["startSeconds"]["basic"]["value"], 1761 played_time=payload["timePlayedSeconds"]["basic"]["displayValue"], 1762 player_count=payload["playerCount"]["basic"]["value"], 1763 team_score=payload["teamScore"]["basic"]["value"], 1764 ) 1765 1766 def deserialize_activity( 1767 self, 1768 payload: typedefs.JSONObject, 1769 /, 1770 ) -> activity.Activity: 1771 period = time.clean_date(payload["period"]) 1772 details = payload["activityDetails"] 1773 ref_id = int(details["referenceId"]) 1774 instance_id = int(details["instanceId"]) 1775 mode = enums.GameMode(details["mode"]) 1776 modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]] 1777 is_private = details["isPrivate"] 1778 membership_type = enums.MembershipType(int(details["membershipType"])) 1779 1780 # Since we're using the same fields for post activity method 1781 # this check is required since post activity doesn't values values 1782 values = self._deserialize_activity_values(payload["values"]) 1783 1784 return activity.Activity( 1785 net=self._net, 1786 hash=ref_id, 1787 instance_id=instance_id, 1788 mode=mode, 1789 modes=modes, 1790 is_private=is_private, 1791 membership_type=membership_type, 1792 occurred_at=period, 1793 values=values, 1794 ) 1795 1796 def deserialize_activities( 1797 self, payload: typedefs.JSONObject 1798 ) -> iterators.Iterator[activity.Activity]: 1799 return iterators.Iterator( 1800 [ 1801 self.deserialize_activity(activity_) 1802 for activity_ in payload["activities"] 1803 ] 1804 ) 1805 1806 def deserialize_extended_weapon_values( 1807 self, payload: typedefs.JSONObject 1808 ) -> activity.ExtendedWeaponValues: 1809 assists: typing.Optional[int] = None 1810 if raw_assists := payload["values"].get("uniqueWeaponAssists"): 1811 assists = raw_assists["basic"]["value"] 1812 assists_damage: typing.Optional[int] = None 1813 1814 if raw_assists_damage := payload["values"].get("uniqueWeaponAssistDamage"): 1815 assists_damage = raw_assists_damage["basic"]["value"] 1816 1817 return activity.ExtendedWeaponValues( 1818 reference_id=int(payload["referenceId"]), 1819 kills=payload["values"]["uniqueWeaponKills"]["basic"]["value"], 1820 precision_kills=payload["values"]["uniqueWeaponPrecisionKills"]["basic"][ 1821 "value" 1822 ], 1823 assists=assists, 1824 assists_damage=assists_damage, 1825 precision_kills_percentage=( 1826 payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"]["value"], 1827 payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"][ 1828 "displayValue" 1829 ], 1830 ), 1831 ) 1832 1833 def _deserialize_extended_values( 1834 self, payload: typedefs.JSONObject 1835 ) -> activity.ExtendedValues: 1836 weapons: typing.Optional[ 1837 collections.Collection[activity.ExtendedWeaponValues] 1838 ] = None 1839 1840 if raw_weapons := payload.get("weapons"): 1841 weapons = [ 1842 self.deserialize_extended_weapon_values(value) for value in raw_weapons 1843 ] 1844 1845 return activity.ExtendedValues( 1846 precision_kills=payload["values"]["precisionKills"]["basic"]["value"], 1847 grenade_kills=payload["values"]["weaponKillsGrenade"]["basic"]["value"], 1848 melee_kills=payload["values"]["weaponKillsMelee"]["basic"]["value"], 1849 super_kills=payload["values"]["weaponKillsSuper"]["basic"]["value"], 1850 ability_kills=payload["values"]["weaponKillsAbility"]["basic"]["value"], 1851 weapons=weapons, 1852 ) 1853 1854 def deserialize_post_activity_player( 1855 self, payload: typedefs.JSONObject, / 1856 ) -> activity.PostActivityPlayer: 1857 player = payload["player"] 1858 1859 class_hash: typedefs.NoneOr[int] = None 1860 if (class_hash := player.get("classHash")) is not None: 1861 class_hash = class_hash 1862 1863 race_hash: typedefs.NoneOr[int] = None 1864 if (race_hash := player.get("raceHash")) is not None: 1865 race_hash = race_hash 1866 1867 gender_hash: typedefs.NoneOr[int] = None 1868 if (gender_hash := player.get("genderHash")) is not None: 1869 gender_hash = gender_hash 1870 1871 character_class: undefined.UndefinedOr[str] = undefined.UNDEFINED 1872 if ( 1873 character_class := player.get("characterClass") 1874 ) and not typedefs.is_unknown(character_class): 1875 character_class = character_class 1876 1877 character_level: typedefs.NoneOr[int] = None 1878 if (character_level := player.get("characterLevel")) is not None: 1879 character_level = character_level 1880 1881 return activity.PostActivityPlayer( 1882 standing=int(payload["standing"]), 1883 score=int(payload["score"]["basic"]["value"]), 1884 character_id=payload["characterId"], 1885 destiny_user=self.deserialize_destiny_membership(player["destinyUserInfo"]), 1886 character_class=character_class, 1887 character_level=character_level, 1888 race_hash=race_hash, 1889 gender_hash=gender_hash, 1890 class_hash=class_hash, 1891 light_level=int(player["lightLevel"]), 1892 emblem_hash=int(player["emblemHash"]), 1893 values=self._deserialize_activity_values(payload["values"]), 1894 extended_values=self._deserialize_extended_values(payload["extended"]), 1895 ) 1896 1897 def _deserialize_post_activity_team( 1898 self, payload: typedefs.JSONObject 1899 ) -> activity.PostActivityTeam: 1900 return activity.PostActivityTeam( 1901 id=payload["teamId"], 1902 is_defeated=bool(payload["standing"]["basic"]["value"]), 1903 score=int(payload["score"]["basic"]["value"]), 1904 name=payload["teamName"], 1905 ) 1906 1907 def deserialize_post_activity( 1908 self, payload: typedefs.JSONObject 1909 ) -> activity.PostActivity: 1910 period = time.clean_date(payload["period"]) 1911 details = payload["activityDetails"] 1912 ref_id = int(details["referenceId"]) 1913 instance_id = int(details["instanceId"]) 1914 mode = enums.GameMode(details["mode"]) 1915 modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]] 1916 is_private = details["isPrivate"] 1917 membership_type = enums.MembershipType(int(details["membershipType"])) 1918 return activity.PostActivity( 1919 net=self._net, 1920 hash=ref_id, 1921 membership_type=membership_type, 1922 instance_id=instance_id, 1923 mode=mode, 1924 modes=modes, 1925 is_private=is_private, 1926 occurred_at=period, 1927 starting_phase=int(payload["startingPhaseIndex"]), 1928 players=[ 1929 self.deserialize_post_activity_player(player) 1930 for player in payload["entries"] 1931 ], 1932 teams=[ 1933 self._deserialize_post_activity_team(team) for team in payload["teams"] 1934 ], 1935 ) 1936 1937 def _deserialize_aggregated_activity_values( 1938 self, payload: typedefs.JSONObject 1939 ) -> activity.AggregatedActivityValues: 1940 # This ID is always the same for all aggregated values. 1941 activity_id = int(payload["fastestCompletionMsForActivity"]["activityId"]) 1942 1943 return activity.AggregatedActivityValues( 1944 id=activity_id, 1945 fastest_completion_time=( 1946 int(payload["fastestCompletionMsForActivity"]["basic"]["value"]), 1947 payload["fastestCompletionMsForActivity"]["basic"]["displayValue"], 1948 ), 1949 completions=int(payload["activityCompletions"]["basic"]["value"]), 1950 kills=int(payload["activityKills"]["basic"]["value"]), 1951 deaths=int(payload["activityDeaths"]["basic"]["value"]), 1952 assists=int(payload["activityAssists"]["basic"]["value"]), 1953 seconds_played=( 1954 int(payload["activitySecondsPlayed"]["basic"]["value"]), 1955 payload["activitySecondsPlayed"]["basic"]["displayValue"], 1956 ), 1957 wins=int(payload["activityWins"]["basic"]["value"]), 1958 goals_missed=int(payload["activityGoalsMissed"]["basic"]["value"]), 1959 special_actions=int(payload["activitySpecialActions"]["basic"]["value"]), 1960 best_goals_hit=int(payload["activityBestGoalsHit"]["basic"]["value"]), 1961 best_single_score=int( 1962 payload["activityBestSingleGameScore"]["basic"]["value"] 1963 ), 1964 goals_hit=int(payload["activityGoalsHit"]["basic"]["value"]), 1965 special_score=int(payload["activitySpecialScore"]["basic"]["value"]), 1966 kd_assists=int(payload["activityKillsDeathsAssists"]["basic"]["value"]), 1967 kd_ratio=float( 1968 payload["activityKillsDeathsAssists"]["basic"]["displayValue"] 1969 ), 1970 precision_kills=int(payload["activityPrecisionKills"]["basic"]["value"]), 1971 ) 1972 1973 def deserialize_aggregated_activity( 1974 self, payload: typedefs.JSONObject 1975 ) -> activity.AggregatedActivity: 1976 return activity.AggregatedActivity( 1977 hash=int(payload["activityHash"]), 1978 values=self._deserialize_aggregated_activity_values(payload["values"]), 1979 ) 1980 1981 def deserialize_aggregated_activities( 1982 self, payload: typedefs.JSONObject 1983 ) -> iterators.Iterator[activity.AggregatedActivity]: 1984 return iterators.Iterator( 1985 [ 1986 self.deserialize_aggregated_activity(activity) 1987 for activity in payload["activities"] 1988 ] 1989 ) 1990 1991 def deserialize_linked_profiles( 1992 self, payload: typedefs.JSONObject 1993 ) -> profile.LinkedProfile: 1994 bungie_user = self.deserialize_partial_bungie_user(payload["bnetMembership"]) 1995 error_profiles_vec: typing.MutableSequence[user.DestinyMembership] = [] 1996 profiles_vec: typing.MutableSequence[user.DestinyMembership] = [] 1997 1998 if raw_profile := payload.get("profiles"): 1999 for pfile in raw_profile: 2000 profiles_vec.append(self.deserialize_destiny_membership(pfile)) 2001 2002 if raw_profiles_with_errors := payload.get("profilesWithErrors"): 2003 for raw_error_pfile in raw_profiles_with_errors: 2004 if error_pfile := raw_error_pfile.get("infoCard"): 2005 error_profiles_vec.append( 2006 self.deserialize_destiny_membership(error_pfile) 2007 ) 2008 2009 return profile.LinkedProfile( 2010 bungie=bungie_user, 2011 profiles=profiles_vec, 2012 profiles_with_errors=error_profiles_vec, 2013 ) 2014 2015 def deserialize_clan_banners( 2016 self, payload: typedefs.JSONObject 2017 ) -> collections.Sequence[clans.ClanBanner]: 2018 banners_seq: typing.MutableSequence[clans.ClanBanner] = [] 2019 if banners := payload.get("clanBannerDecals"): 2020 for k, v in banners.items(): 2021 banner_obj = clans.ClanBanner( 2022 id=int(k), 2023 foreground=assets.Image(v["foregroundPath"]), 2024 background=assets.Image(v["backgroundPath"]), 2025 ) 2026 banners_seq.append(banner_obj) 2027 return banners_seq 2028 2029 def deserialize_public_milestone_content( 2030 self, payload: typedefs.JSONObject 2031 ) -> milestones.MilestoneContent: 2032 items_categoris: typedefs.NoneOr[milestones.MilestoneItems] = None 2033 if raw_categories := payload.get("itemCategories"): 2034 for item in raw_categories: 2035 title = undefined.UNDEFINED 2036 if raw_title := item.get("title"): 2037 if raw_title != typedefs.Unknown: 2038 title = raw_title 2039 if raw_hashes := item.get("itemHashes"): 2040 hashes: collections.Sequence[int] = raw_hashes 2041 2042 items_categoris = milestones.MilestoneItems(title=title, hashes=hashes) 2043 2044 about = undefined.UNDEFINED 2045 if (raw_about := payload["about"]) != typedefs.Unknown: 2046 about = raw_about 2047 2048 status = undefined.UNDEFINED 2049 if (raw_status := payload["status"]) != typedefs.Unknown: 2050 status = raw_status 2051 2052 tips: typing.MutableSequence[undefined.UndefinedOr[str]] = [] 2053 if raw_tips := payload.get("tips"): 2054 for raw_tip in raw_tips: 2055 if raw_tip == typedefs.Unknown: 2056 raw_tip = undefined.UNDEFINED 2057 tips.append(raw_tip) 2058 2059 return milestones.MilestoneContent( 2060 about=about, status=status, tips=tips, items=items_categoris 2061 ) 2062 2063 def deserialize_friend(self, payload: typedefs.JSONObject, /) -> friends.Friend: 2064 name = undefined.UNDEFINED 2065 if (raw_name := payload["bungieGlobalDisplayName"]) != typedefs.Unknown: 2066 name = raw_name 2067 2068 bungie_user: typedefs.NoneOr[user.BungieUser] = None 2069 2070 if raw_bungie_user := payload.get("bungieNetUser"): 2071 bungie_user = self.deserialize_bungie_user(raw_bungie_user) 2072 2073 return friends.Friend( 2074 net=self._net, 2075 id=int(payload["lastSeenAsMembershipId"]), 2076 name=name, 2077 code=payload.get("bungieGlobalDisplayNameCode"), 2078 relationship=enums.Relationship(payload["relationship"]), 2079 user=bungie_user, 2080 online_status=enums.Presence(payload["onlineStatus"]), 2081 online_title=payload["onlineTitle"], 2082 type=enums.MembershipType(payload["lastSeenAsBungieMembershipType"]), 2083 ) 2084 2085 def deserialize_friends( 2086 self, payload: typedefs.JSONObject 2087 ) -> collections.Sequence[friends.Friend]: 2088 mut_seq: typing.MutableSequence[friends.Friend] = [] 2089 if raw_friends := payload.get("friends"): 2090 for friend in raw_friends: 2091 mut_seq.append(self.deserialize_friend(friend)) 2092 return mut_seq 2093 2094 def deserialize_friend_requests( 2095 self, payload: typedefs.JSONObject 2096 ) -> friends.FriendRequestView: 2097 incoming: typing.MutableSequence[friends.Friend] = [] 2098 outgoing: typing.MutableSequence[friends.Friend] = [] 2099 2100 if raw_incoming_requests := payload.get("incomingRequests"): 2101 for incoming_request in raw_incoming_requests: 2102 incoming.append(self.deserialize_friend(incoming_request)) 2103 2104 if raw_outgoing_requests := payload.get("outgoingRequests"): 2105 for outgoing_request in raw_outgoing_requests: 2106 outgoing.append(self.deserialize_friend(outgoing_request)) 2107 2108 return friends.FriendRequestView(incoming=incoming, outgoing=outgoing) 2109 2110 def _set_fireteam_fields( 2111 self, payload: typedefs.JSONObject, total_results: typing.Optional[int] = None 2112 ) -> fireteams.Fireteam: 2113 activity_type = fireteams.FireteamActivity(payload["activityType"]) 2114 return fireteams.Fireteam( 2115 id=int(payload["fireteamId"]), 2116 group_id=int(payload["groupId"]), 2117 platform=fireteams.FireteamPlatform(payload["platform"]), 2118 is_immediate=payload["isImmediate"], 2119 activity_type=activity_type, 2120 owner_id=int(payload["ownerMembershipId"]), 2121 player_slot_count=payload["playerSlotCount"], 2122 available_player_slots=payload["availablePlayerSlotCount"], 2123 available_alternate_slots=payload["availableAlternateSlotCount"], 2124 title=payload["title"], 2125 date_created=time.clean_date(payload["dateCreated"]), 2126 is_public=payload["isPublic"], 2127 locale=fireteams.FireteamLanguage(payload["locale"]), 2128 is_valid=payload["isValid"], 2129 last_modified=time.clean_date(payload["datePlayerModified"]), 2130 total_results=total_results or 0, 2131 ) 2132 2133 def deserialize_fireteams( 2134 self, payload: typedefs.JSONObject 2135 ) -> typedefs.NoneOr[collections.Sequence[fireteams.Fireteam]]: 2136 fireteams_: typing.MutableSequence[fireteams.Fireteam] = [] 2137 2138 result: list[typedefs.JSONObject] 2139 if not (result := payload["results"]): 2140 return None 2141 for elem in result: 2142 fireteams_.append( 2143 self._set_fireteam_fields( 2144 elem, total_results=int(payload["totalResults"]) 2145 ) 2146 ) 2147 return fireteams_ 2148 2149 def deserialize_fireteam_destiny_users( 2150 self, payload: typedefs.JSONObject 2151 ) -> fireteams.FireteamUser: 2152 destiny_obj = self.deserialize_destiny_membership(payload) 2153 # We could helpers.just return a DestinyMembership object but this is 2154 # missing the fireteam display name and id fields. 2155 return fireteams.FireteamUser( 2156 net=self._net, 2157 id=destiny_obj.id, 2158 code=destiny_obj.code, 2159 icon=destiny_obj.icon, 2160 types=destiny_obj.types, 2161 type=destiny_obj.type, 2162 is_public=destiny_obj.is_public, 2163 crossave_override=destiny_obj.crossave_override, 2164 name=destiny_obj.name, 2165 last_seen_name=destiny_obj.last_seen_name, 2166 fireteam_display_name=payload["FireteamDisplayName"], 2167 fireteam_membership_id=enums.MembershipType( 2168 payload["FireteamMembershipType"] 2169 ), 2170 ) 2171 2172 def deserialize_fireteam_members( 2173 self, payload: typedefs.JSONObject, *, alternatives: bool = False 2174 ) -> collections.Sequence[fireteams.FireteamMember]: 2175 members_: list[fireteams.FireteamMember] = [] 2176 if members := payload.get("Members" if not alternatives else "Alternates"): 2177 for member in members: 2178 bungie_fields = self.deserialize_partial_bungie_user(member) 2179 members_fields = fireteams.FireteamMember( 2180 destiny_user=self.deserialize_fireteam_destiny_users(member), 2181 has_microphone=member["hasMicrophone"], 2182 character_id=int(member["characterId"]), 2183 date_joined=time.clean_date(member["dateJoined"]), 2184 last_platform_invite_date=time.clean_date( 2185 member["lastPlatformInviteAttemptDate"] 2186 ), 2187 last_platform_invite_result=int( 2188 member["lastPlatformInviteAttemptResult"] 2189 ), 2190 net=self._net, 2191 name=bungie_fields.name, 2192 id=bungie_fields.id, 2193 icon=bungie_fields.icon, 2194 is_public=bungie_fields.is_public, 2195 crossave_override=bungie_fields.crossave_override, 2196 types=bungie_fields.types, 2197 type=bungie_fields.type, 2198 ) 2199 members_.append(members_fields) 2200 return members_ 2201 2202 # TODO: Don't return union here. In general fix this method. 2203 def deserialize_available_fireteams( 2204 self, 2205 data: typedefs.JSONObject, 2206 *, 2207 no_results: bool = False, 2208 ) -> typing.Union[ 2209 fireteams.AvailableFireteam, collections.Sequence[fireteams.AvailableFireteam] 2210 ]: 2211 fireteams_: list[fireteams.AvailableFireteam] = [] 2212 2213 # This needs to be used outside the results 2214 # JSON key. 2215 if no_results: 2216 payload = data.copy() 2217 2218 if (results := payload.get("results")) is not None: 2219 for fireteam in results: 2220 found_fireteams = self._set_fireteam_fields(fireteam["Summary"]) 2221 fireteams_fields = fireteams.AvailableFireteam( 2222 id=found_fireteams.id, 2223 group_id=found_fireteams.group_id, 2224 platform=found_fireteams.platform, 2225 activity_type=found_fireteams.activity_type, 2226 is_immediate=found_fireteams.is_immediate, 2227 is_public=found_fireteams.is_public, 2228 is_valid=found_fireteams.is_valid, 2229 owner_id=found_fireteams.owner_id, 2230 player_slot_count=found_fireteams.player_slot_count, 2231 available_player_slots=found_fireteams.available_player_slots, 2232 available_alternate_slots=found_fireteams.available_alternate_slots, 2233 title=found_fireteams.title, 2234 date_created=found_fireteams.date_created, 2235 locale=found_fireteams.locale, 2236 last_modified=found_fireteams.last_modified, 2237 total_results=found_fireteams.total_results, 2238 members=self.deserialize_fireteam_members(payload), 2239 alternatives=self.deserialize_fireteam_members( 2240 payload, alternatives=True 2241 ), 2242 ) 2243 if no_results: 2244 return fireteams_fields 2245 else: 2246 fireteams_.append(fireteams_fields) 2247 return fireteams_ 2248 2249 def deserialize_fireteam_party( 2250 self, payload: typedefs.JSONObject 2251 ) -> fireteams.FireteamParty: 2252 last_destination_hash: typing.Optional[int] = None 2253 if raw_dest_hash := payload.get("lastOrbitedDestinationHash"): 2254 last_destination_hash = int(raw_dest_hash) 2255 2256 return fireteams.FireteamParty( 2257 members=[ 2258 self._deserialize_fireteam_party_member(member) 2259 for member in payload["partyMembers"] 2260 ], 2261 activity=self._deserialize_fireteam_party_current_activity( 2262 payload["currentActivity"] 2263 ), 2264 settings=self._deserialize_fireteam_party_settings(payload["joinability"]), 2265 last_destination_hash=last_destination_hash, 2266 tracking=payload["tracking"], 2267 ) 2268 2269 def _deserialize_fireteam_party_member( 2270 self, payload: typedefs.JSONObject 2271 ) -> fireteams.FireteamPartyMember: 2272 status = fireteams.FireteamPartyMemberState(payload["status"]) 2273 displayname: undefined.UndefinedOr[str] = undefined.UNDEFINED 2274 if raw_name := payload.get("displayName"): 2275 displayname = raw_name 2276 2277 return fireteams.FireteamPartyMember( 2278 membership_id=int(payload["membershipId"]), 2279 emblem_hash=int(payload["emblemHash"]), 2280 status=status, 2281 display_name=displayname, 2282 ) 2283 2284 def _deserialize_fireteam_party_current_activity( 2285 self, payload: typedefs.JSONObject 2286 ) -> fireteams.FireteamPartyCurrentActivity: 2287 start_date: typing.Optional[datetime.datetime] = None 2288 if raw_start_date := payload.get("startTime"): 2289 start_date = time.clean_date(raw_start_date) 2290 2291 end_date: typing.Optional[datetime.datetime] = None 2292 if raw_end_date := payload.get("endTime"): 2293 end_date = time.clean_date(raw_end_date) 2294 return fireteams.FireteamPartyCurrentActivity( 2295 start_time=start_date, 2296 end_time=end_date, 2297 score=float(payload["score"]), 2298 highest_opposing_score=float(payload["highestOpposingFactionScore"]), 2299 opponenst_count=int(payload["numberOfOpponents"]), 2300 player_count=int(payload["numberOfPlayers"]), 2301 ) 2302 2303 def _deserialize_fireteam_party_settings( 2304 self, payload: typedefs.JSONObject 2305 ) -> fireteams.FireteamPartySettings: 2306 closed_reasons = enums.ClosedReasons(payload["closedReasons"]) 2307 return fireteams.FireteamPartySettings( 2308 open_slots=int(payload["openSlots"]), 2309 privacy_setting=enums.PrivacySetting(int(payload["privacySetting"])), 2310 closed_reasons=closed_reasons, 2311 ) 2312 2313 def deserialize_seasonal_artifact( 2314 self, payload: typedefs.JSONObject 2315 ) -> season.Artifact: 2316 if raw_artifact := payload.get("seasonalArtifact"): 2317 if points := raw_artifact.get("pointProgression"): 2318 points_prog = progressions.Progression( 2319 hash=points["progressionHash"], 2320 level=points["level"], 2321 cap=points["levelCap"], 2322 daily_limit=points["dailyLimit"], 2323 weekly_limit=points["weeklyLimit"], 2324 current_progress=points["currentProgress"], 2325 daily_progress=points["dailyProgress"], 2326 needed=points["progressToNextLevel"], 2327 next_level=points["nextLevelAt"], 2328 ) 2329 2330 if bonus := raw_artifact.get("powerBonusProgression"): 2331 power_bonus_prog = progressions.Progression( 2332 hash=bonus["progressionHash"], 2333 level=bonus["level"], 2334 cap=bonus["levelCap"], 2335 daily_limit=bonus["dailyLimit"], 2336 weekly_limit=bonus["weeklyLimit"], 2337 current_progress=bonus["currentProgress"], 2338 daily_progress=bonus["dailyProgress"], 2339 needed=bonus["progressToNextLevel"], 2340 next_level=bonus["nextLevelAt"], 2341 ) 2342 artifact = season.Artifact( 2343 hash=raw_artifact["artifactHash"], 2344 power_bonus=raw_artifact["powerBonus"], 2345 acquired_points=raw_artifact["pointsAcquired"], 2346 bonus=power_bonus_prog, 2347 points=points_prog, 2348 ) 2349 return artifact 2350 2351 def deserialize_profile_progression( 2352 self, payload: typedefs.JSONObject 2353 ) -> profile.ProfileProgression: 2354 return profile.ProfileProgression( 2355 artifact=self.deserialize_seasonal_artifact(payload["data"]), 2356 checklist={ 2357 int(check_id): checklists 2358 for check_id, checklists in payload["data"]["checklists"].items() 2359 }, 2360 ) 2361 2362 def deserialize_instanced_item( 2363 self, payload: typedefs.JSONObject 2364 ) -> items.ItemInstance: 2365 damage_type_hash: typing.Optional[int] = None 2366 if raw_damagetype_hash := payload.get("damageTypeHash"): 2367 damage_type_hash = int(raw_damagetype_hash) 2368 2369 required_hashes: typing.Optional[collections.Collection[int]] = None 2370 if raw_required_hashes := payload.get("unlockHashesRequiredToEquip"): 2371 required_hashes = [int(raw_hash) for raw_hash in raw_required_hashes] 2372 2373 breaker_type: typing.Optional[items.ItemBreakerType] = None 2374 if raw_break_type := payload.get("breakerType"): 2375 breaker_type = items.ItemBreakerType(int(raw_break_type)) 2376 2377 breaker_type_hash: typing.Optional[int] = None 2378 if raw_break_type_hash := payload.get("breakerTypeHash"): 2379 breaker_type_hash = int(raw_break_type_hash) 2380 2381 energy: typing.Optional[items.ItemEnergy] = None 2382 if raw_energy := payload.get("energy"): 2383 energy = self.deserialize_item_energy(raw_energy) 2384 2385 primary_stats = None 2386 if raw_primary_stats := payload.get("primaryStat"): 2387 primary_stats = self.deserialize_item_stats_view(raw_primary_stats) 2388 2389 return items.ItemInstance( 2390 damage_type=enums.DamageType(int(payload["damageType"])), 2391 damage_type_hash=damage_type_hash, 2392 primary_stat=primary_stats, 2393 item_level=int(payload["itemLevel"]), 2394 quality=int(payload["quality"]), 2395 is_equipped=payload["isEquipped"], 2396 can_equip=payload["canEquip"], 2397 equip_required_level=int(payload["equipRequiredLevel"]), 2398 required_equip_unlock_hashes=required_hashes, 2399 cant_equip_reason=int(payload["cannotEquipReason"]), 2400 breaker_type=breaker_type, 2401 breaker_type_hash=breaker_type_hash, 2402 energy=energy, 2403 ) 2404 2405 def deserialize_item_energy(self, payload: typedefs.JSONObject) -> items.ItemEnergy: 2406 energy_hash: typing.Optional[int] = None 2407 if raw_energy_hash := payload.get("energyTypeHash"): 2408 energy_hash = int(raw_energy_hash) 2409 2410 return items.ItemEnergy( 2411 hash=energy_hash, 2412 type=items.ItemEnergyType(int(payload["energyType"])), 2413 capacity=int(payload["energyCapacity"]), 2414 used_energy=int(payload["energyUsed"]), 2415 unused_energy=int(payload["energyUnused"]), 2416 ) 2417 2418 def deserialize_item_perk(self, payload: typedefs.JSONObject) -> items.ItemPerk: 2419 perk_hash: typing.Optional[int] = None 2420 if raw_perk_hash := payload.get("perkHash"): 2421 perk_hash = int(raw_perk_hash) 2422 2423 return items.ItemPerk( 2424 hash=perk_hash, 2425 icon=assets.Image(payload["iconPath"]), 2426 is_active=payload["isActive"], 2427 is_visible=payload["visible"], 2428 ) 2429 2430 def deserialize_item_socket(self, payload: typedefs.JSONObject) -> items.ItemSocket: 2431 plug_hash: typing.Optional[int] = None 2432 if raw_plug_hash := payload.get("plugHash"): 2433 plug_hash = int(raw_plug_hash) 2434 2435 enable_fail_indexes: typing.Optional[list[int]] = None 2436 if raw_indexes := payload.get("enableFailIndexes"): 2437 enable_fail_indexes = [int(index) for index in raw_indexes] 2438 2439 return items.ItemSocket( 2440 plug_hash=plug_hash, 2441 is_enabled=payload["isEnabled"], 2442 enable_fail_indexes=enable_fail_indexes, 2443 is_visible=payload.get("visible"), 2444 ) 2445 2446 def deserialize_item_stats_view( 2447 self, payload: typedefs.JSONObject 2448 ) -> items.ItemStatsView: 2449 return items.ItemStatsView( 2450 stat_hash=payload.get("statHash"), value=payload.get("value") 2451 ) 2452 2453 def deserialize_plug_item_state( 2454 self, payload: typedefs.JSONObject 2455 ) -> items.PlugItemState: 2456 item_hash: typing.Optional[int] = None 2457 if raw_item_hash := payload.get("plugItemHash"): 2458 item_hash = int(raw_item_hash) 2459 2460 insert_fail_indexes: typedefs.NoneOr[list[int]] = None 2461 if raw_fail_indexes := payload.get("insertFailIndexes"): 2462 insert_fail_indexes = [int(k) for k in raw_fail_indexes] 2463 2464 enable_fail_indexes: typedefs.NoneOr[list[int]] = None 2465 if raw_enabled_indexes := payload.get("enableFailIndexes"): 2466 enable_fail_indexes = [int(k) for k in raw_enabled_indexes] 2467 2468 return items.PlugItemState( 2469 item_hash=item_hash, 2470 insert_fail_indexes=insert_fail_indexes, 2471 enable_fail_indexes=enable_fail_indexes, 2472 is_enabled=payload["enabled"], 2473 can_insert=payload["canInsert"], 2474 )
The base deserialization factory class for all aiobungie objects.
This entity factory is used to deserialize JSON responses from the REST client and turning them
into a aiobungie.crates Python classes.
73 def deserialize_bungie_user(self, data: typedefs.JSONObject) -> user.BungieUser: 74 return user.BungieUser( 75 id=int(data["membershipId"]), 76 created_at=time.clean_date(data["firstAccess"]), 77 name=data.get("cachedBungieGlobalDisplayName", undefined.UNDEFINED), 78 is_deleted=data["isDeleted"], 79 about=data["about"], 80 updated_at=time.clean_date(data["lastUpdate"]), 81 psn_name=data.get("psnDisplayName", None), 82 stadia_name=data.get("stadiaDisplayName", None), 83 steam_name=data.get("steamDisplayName", None), 84 twitch_name=data.get("twitchDisplayName", None), 85 blizzard_name=data.get("blizzardDisplayName", None), 86 status=data["statusText"], 87 locale=data["locale"], 88 picture=assets.Image(path=str(data["profilePicturePath"])), 89 code=data.get("cachedBungieGlobalDisplayNameCode", None), 90 unique_name=data.get("uniqueName", None), 91 theme_id=int(data["profileTheme"]), 92 show_activity=bool(data["showActivity"]), 93 theme_name=data["profileThemeName"], 94 display_title=data["userTitleDisplay"], 95 )
Deserialize a raw JSON Bungie.net user only payload into a user object.
This only returns the Bungie.net user and not the Destiny memberships.
Parameters
- data (
aiobungie.typedefs.JSONObject): The JSON data/payload.
Returns
aiobungie.crates.BungieUser: A Bungie user.
97 def deserialize_partial_bungie_user( 98 self, payload: typedefs.JSONObject 99 ) -> user.PartialBungieUser: 100 return user.PartialBungieUser( 101 net=self._net, 102 types=[ 103 enums.MembershipType(type_) 104 for type_ in payload.get("applicableMembershipTypes", []) 105 ], 106 name=payload.get("displayName", undefined.UNDEFINED), 107 id=int(payload["membershipId"]), 108 crossave_override=enums.MembershipType(payload["crossSaveOverride"]), 109 is_public=payload["isPublic"], 110 icon=assets.Image(payload.get("iconPath", "")), 111 type=enums.MembershipType(payload["membershipType"]), 112 )
Deserialize a raw JSON of a partial bungieNetUserInfo.
A partial user is a bungie.net user payload with missing information from
the main BungieUser object.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.PartialBungieUser: A partial bungie user.
114 def deserialize_destiny_membership( 115 self, payload: typedefs.JSONObject 116 ) -> user.DestinyMembership: 117 name: undefined.UndefinedOr[str] = undefined.UNDEFINED 118 if ( 119 raw_name := payload.get("bungieGlobalDisplayName", "") 120 ) and not typedefs.is_unknown(raw_name): 121 name = raw_name 122 123 return user.DestinyMembership( 124 net=self._net, 125 id=int(payload["membershipId"]), 126 name=name, 127 code=payload.get("bungieGlobalDisplayNameCode", None), 128 last_seen_name=payload.get("LastSeenDisplayName") 129 or payload.get("displayName") # noqa: W503 130 or "", # noqa: W503 131 type=enums.MembershipType(payload["membershipType"]), 132 is_public=payload["isPublic"], 133 crossave_override=enums.MembershipType(payload["crossSaveOverride"]), 134 icon=assets.Image(payload.get("iconPath", "")), 135 types=[ 136 enums.MembershipType(type_) 137 for type_ in payload.get("applicableMembershipTypes", []) 138 ], 139 )
Deserialize a raw JSON of destinyUserInfo destiny membership information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.user.DestinyMembership: A Destiny 2 membership.
141 def deserialize_destiny_memberships( 142 self, data: typedefs.JSONArray 143 ) -> collections.Sequence[user.DestinyMembership]: 144 return [self.deserialize_destiny_membership(membership) for membership in data]
Deserialize a raw JSON payload/array of destinyUserInfo.
Parameters
- payload (
aiobungie.typedefs.JSONArray): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.user.DestinyMembership]: A sequence of Destiny 2 memberships.
146 def deserialize_user(self, data: typedefs.JSONObject) -> user.User: 147 primary_membership_id: typing.Optional[int] = None 148 if raw_primary_id := data.get("primaryMembershipId"): 149 primary_membership_id = int(raw_primary_id) 150 151 return user.User( 152 bungie=self.deserialize_bungie_user(data["bungieNetUser"]), 153 destiny=self.deserialize_destiny_memberships(data["destinyMemberships"]), 154 primary_membership_id=primary_membership_id, 155 )
Deserialize a raw JSON results of fetched user memberships and Bungie.net user its their id.
Parameters
- data (
aiobungie.typedefs.JSONObject): The JSON data/payload.
Returns
aiobungie.crates.User: A user object.
157 def deserialize_searched_user( 158 self, payload: typedefs.JSONObject 159 ) -> user.SearchableDestinyUser: 160 name: undefined.UndefinedOr[str] = undefined.UNDEFINED 161 if (raw_name := payload["bungieGlobalDisplayName"]) and not typedefs.is_unknown( 162 raw_name 163 ): 164 name = raw_name 165 166 code: typing.Optional[int] = None 167 if raw_code := payload.get("bungieGlobalDisplayNameCode"): 168 code = int(raw_code) 169 170 bungie_id: typing.Optional[int] = None 171 if raw_bungie_id := payload.get("bungieNetMembershipId"): 172 bungie_id = int(raw_bungie_id) 173 174 return user.SearchableDestinyUser( 175 name=name, 176 code=code, 177 bungie_id=bungie_id, 178 memberships=self.deserialize_destiny_memberships( 179 payload["destinyMemberships"] 180 ), 181 )
Deserialize the results of user search details.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.SearchableDestinyUser: The searched for Destiny 2 membership.
183 def deserialize_user_credentials( 184 self, payload: typedefs.JSONArray 185 ) -> collections.Sequence[user.UserCredentials]: 186 return [ 187 user.UserCredentials( 188 type=enums.CredentialType(int(creds["credentialType"])), 189 display_name=creds["credentialDisplayName"], 190 is_public=creds["isPublic"], 191 self_as_string=creds.get("credentialAsString", undefined.UNDEFINED), 192 ) 193 for creds in payload 194 ]
Deserialize a JSON array of Bungie user credentials.
Parameters
- payload (
aiobungie.typedefs.JSONArray): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.UserCredentials]: A sequence of user's credentials.
196 def deserialize_user_themes( 197 self, payload: typedefs.JSONArray 198 ) -> collections.Sequence[user.UserThemes]: 199 return [ 200 user.UserThemes( 201 id=int(entry["userThemeId"]), 202 name=entry["userThemeName"] 203 if "userThemeName" in entry 204 else undefined.UNDEFINED, 205 description=entry["userThemeDescription"] 206 if "userThemeDescription" in entry 207 else undefined.UNDEFINED, 208 ) 209 for entry in payload 210 ]
Deserialize a raw JSON array of Bungie user themes.
Parameters
- payload (
aiobungie.typedefs.JSONArray): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.user.UserThemes]: A sequence of bungie user themes.
212 def deserialize_clan(self, payload: typedefs.JSONObject) -> clans.Clan: 213 # This is kinda redundant 214 data = payload 215 216 # This is always outside the details. 217 current_user_map: typing.Optional[ 218 collections.Mapping[str, clans.ClanMember] 219 ] = None 220 if raw_current_user_map := payload.get("currentUserMemberMap"): 221 current_user_map = { 222 membership_type: self.deserialize_clan_member(membership) 223 for membership_type, membership in raw_current_user_map.items() 224 } 225 226 try: 227 data = payload["detail"] 228 except KeyError: 229 pass 230 231 id = data["groupId"] 232 name = data["name"] 233 created_at = data["creationDate"] 234 member_count = data["memberCount"] 235 about = data["about"] 236 motto = data["motto"] 237 is_public = data["isPublic"] 238 banner = assets.Image(str(data["bannerPath"])) 239 avatar = assets.Image(str(data["avatarPath"])) 240 tags = data["tags"] 241 type = data["groupType"] 242 243 features = data["features"] 244 features_obj = clans.ClanFeatures( 245 max_members=features["maximumMembers"], 246 max_membership_types=features["maximumMembershipsOfGroupType"], 247 capabilities=features["capabilities"], 248 membership_types=features["membershipTypes"], 249 invite_permissions=features["invitePermissionOverride"], 250 update_banner_permissions=features["updateBannerPermissionOverride"], 251 update_culture_permissions=features["updateCulturePermissionOverride"], 252 join_level=features["joinLevel"], 253 ) 254 255 information: typedefs.JSONObject = data["clanInfo"] 256 progression: collections.Mapping[int, progressions.Progression] = { 257 int(prog_hash): self.deserialize_progressions(prog) 258 for prog_hash, prog in information["d2ClanProgressions"].items() 259 } 260 261 founder: typedefs.NoneOr[clans.ClanMember] = None 262 if raw_founder := payload.get("founder"): 263 founder = self.deserialize_clan_member(raw_founder) 264 265 return clans.Clan( 266 net=self._net, 267 id=int(id), 268 name=name, 269 type=enums.GroupType(type), 270 created_at=time.clean_date(created_at), 271 member_count=member_count, 272 motto=motto, 273 about=about, 274 is_public=is_public, 275 banner=banner, 276 avatar=avatar, 277 tags=tags, 278 features=features_obj, 279 owner=founder, 280 progressions=progression, 281 call_sign=information["clanCallsign"], 282 banner_data=information["clanBannerData"], 283 chat_security=data["chatSecurity"], 284 conversation_id=int(data["conversationId"]), 285 allow_chat=data["allowChat"], 286 theme=data["theme"], 287 current_user_membership=current_user_map, 288 )
Deserialize a raw JSON payload of Bungie clan information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.Clan: A clan owner.
290 def deserialize_clan_member(self, data: typedefs.JSONObject, /) -> clans.ClanMember: 291 destiny_user = self.deserialize_destiny_membership(data["destinyUserInfo"]) 292 return clans.ClanMember( 293 net=self._net, 294 last_seen_name=destiny_user.last_seen_name, 295 id=destiny_user.id, 296 name=destiny_user.name, 297 icon=destiny_user.icon, 298 last_online=time.from_timestamp(int(data["lastOnlineStatusChange"])), 299 group_id=int(data["groupId"]), 300 joined_at=time.clean_date(data["joinDate"]), 301 types=destiny_user.types, 302 is_public=destiny_user.is_public, 303 type=destiny_user.type, 304 code=destiny_user.code, 305 is_online=data["isOnline"], 306 crossave_override=destiny_user.crossave_override, 307 bungie=self.deserialize_partial_bungie_user(data["bungieNetUserInfo"]) 308 if "bungieNetUserInfo" in data 309 else None, 310 member_type=enums.ClanMemberType(int(data["memberType"])), 311 )
Deserialize a JSON payload of a clan member information.
Parameters
- data (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.ClanMember: A clan member.
313 def deserialize_clan_members( 314 self, data: typedefs.JSONObject, / 315 ) -> iterators.Iterator[clans.ClanMember]: 316 return iterators.Iterator( 317 [self.deserialize_clan_member(member) for member in data["results"]] 318 )
Deserialize a JSON payload of a clan members information.
Parameters
- data (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.iterators.Iterator[aiobungie.crates.ClanMember]: An iterator of clan members of the deserialized payload.
320 def deserialize_group_member( 321 self, payload: typedefs.JSONObject 322 ) -> clans.GroupMember: 323 member = payload["member"] 324 return clans.GroupMember( 325 net=self._net, 326 join_date=time.clean_date(member["joinDate"]), 327 group_id=int(member["groupId"]), 328 member_type=enums.ClanMemberType(member["memberType"]), 329 is_online=member["isOnline"], 330 last_online=time.from_timestamp(int(member["lastOnlineStatusChange"])), 331 inactive_memberships=payload.get("areAllMembershipsInactive", None), 332 member=self.deserialize_destiny_membership(member["destinyUserInfo"]), 333 group=self.deserialize_clan(payload["group"]), 334 )
Deserialize a JSON payload of group information for a member.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.typedefs.NoneOr[aiobungie.crates.GroupMember]: A group member. This can returnNoneif nothing was found.
352 def deserialize_clan_conversations( 353 self, payload: typedefs.JSONArray 354 ) -> collections.Sequence[clans.ClanConversation]: 355 return [self._deserialize_clan_conversation(conv) for conv in payload]
Deserialize a JSON array of a clan conversations information.
Parameters
- payload (
aiobungie.typedefs.JSONArray): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.ClanConversation]: A sequence of clan conversations of the deserialized payload.
357 def deserialize_app_owner( 358 self, payload: typedefs.JSONObject 359 ) -> application.ApplicationOwner: 360 return application.ApplicationOwner( 361 net=self._net, 362 name=payload.get("bungieGlobalDisplayName", undefined.UNDEFINED), 363 id=int(payload["membershipId"]), 364 type=enums.MembershipType(payload["membershipType"]), 365 icon=assets.Image(str(payload["iconPath"])), 366 is_public=payload["isPublic"], 367 code=payload.get("bungieGlobalDisplayNameCode", None), 368 )
Deserialize a JSON payload of Bungie Developer portal application owner information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.application.ApplicationOwner: An application owner.
370 def deserialize_app(self, payload: typedefs.JSONObject) -> application.Application: 371 return application.Application( 372 id=int(payload["applicationId"]), 373 name=payload["name"], 374 link=payload["link"], 375 status=payload["status"], 376 redirect_url=payload.get("redirectUrl", None), 377 created_at=time.clean_date(str(payload["creationDate"])), 378 published_at=time.clean_date(str(payload["firstPublished"])), 379 owner=self.deserialize_app_owner(payload["team"][0]["user"]), # type: ignore 380 scope=payload.get("scope", undefined.UNDEFINED), 381 )
Deserialize a JSON payload of Bungie Developer portal application information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.application.Application: An application.
403 def deserialize_profile(self, payload: typedefs.JSONObject, /) -> profile.Profile: 404 payload = payload["data"] 405 id = int(payload["userInfo"]["membershipId"]) 406 name = payload["userInfo"]["displayName"] 407 is_public = payload["userInfo"]["isPublic"] 408 type = enums.MembershipType(payload["userInfo"]["membershipType"]) 409 last_played = time.clean_date(str(payload["dateLastPlayed"])) 410 character_ids = [int(cid) for cid in payload["characterIds"]] 411 power_cap = payload["currentSeasonRewardPowerCap"] 412 413 return profile.Profile( 414 id=int(id), 415 name=name, 416 is_public=is_public, 417 type=type, 418 last_played=last_played, 419 character_ids=character_ids, 420 power_cap=power_cap, 421 net=self._net, 422 )
Deserialize a JSON payload of Bungie.net profile information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.Profile: A profile object of the deserialized payload.
424 def deserialize_profile_item( 425 self, payload: typedefs.JSONObject 426 ) -> profile.ProfileItemImpl: 427 instance_id: typing.Optional[int] = None 428 if raw_instance_id := payload.get("itemInstanceId"): 429 instance_id = int(raw_instance_id) 430 431 version_number: typing.Optional[int] = None 432 if raw_version := payload.get("versionNumber"): 433 version_number = int(raw_version) 434 435 transfer_status = enums.TransferStatus(payload["transferStatus"]) 436 437 return profile.ProfileItemImpl( 438 net=self._net, 439 hash=payload["itemHash"], 440 quantity=payload["quantity"], 441 bind_status=enums.ItemBindStatus(payload["bindStatus"]), 442 location=enums.ItemLocation(payload["location"]), 443 bucket=payload["bucketHash"], 444 transfer_status=transfer_status, 445 lockable=payload["lockable"], 446 state=enums.ItemState(payload["state"]), 447 dismantle_permissions=payload["dismantlePermission"], 448 is_wrapper=payload["isWrapper"], 449 instance_id=instance_id, 450 version_number=version_number, 451 ornament_id=payload.get("overrideStyleItemHash"), 452 )
Deserialize a JSON payload of a singular profile component item.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.ProfileItemImpl: Implementation of a Destiny 2 profile component item.
454 def deserialize_objectives(self, payload: typedefs.JSONObject) -> records.Objective: 455 return records.Objective( 456 net=self._net, 457 hash=payload["objectiveHash"], 458 visible=payload["visible"], 459 complete=payload["complete"], 460 completion_value=payload["completionValue"], 461 progress=payload.get("progress"), 462 destination_hash=payload.get("destinationHash"), 463 activity_hash=payload.get("activityHash"), 464 )
Deserialize a JSON payload of an objective found in a record profile component.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
aiobungie.crates.records.Objective: A record objective object.
466 def deserialize_records( 467 self, 468 payload: typedefs.JSONObject, 469 scores: typing.Optional[records.RecordScores] = None, 470 **nodes: int, 471 ) -> records.Record: 472 objectives: typing.Optional[list[records.Objective]] = None 473 interval_objectives: typing.Optional[list[records.Objective]] = None 474 record_state: typedefs.IntAnd[records.RecordState] 475 476 record_state = records.RecordState(payload["state"]) 477 478 if raw_objs := payload.get("objectives"): 479 objectives = [self.deserialize_objectives(obj) for obj in raw_objs] 480 481 if raw_interval_objs := payload.get("intervalObjectives"): 482 interval_objectives = [ 483 self.deserialize_objectives(obj) for obj in raw_interval_objs 484 ] 485 486 return records.Record( 487 scores=scores, 488 categories_node_hash=nodes.get("categories_hash", undefined.UNDEFINED), 489 seals_node_hash=nodes.get("seals_hash", undefined.UNDEFINED), 490 state=record_state, 491 objectives=objectives, 492 interval_objectives=interval_objectives, 493 redeemed_count=payload.get("intervalsRedeemedCount", 0), 494 completion_times=payload.get("completedCount", None), 495 reward_visibility=payload.get("rewardVisibility"), 496 )
Deserialize a JSON object of a profile record component.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON object payload - scores (
typing.Optional[records.RecordScores]): The records scores object. This exists only to keep the signature ofaiobungie.crates.CharacterRecordwith the record object. As it will always beNonein that object. - **nodes (
int): An int kwargs use to grab the node hashes while deserializing components.
Returns
aiobungie.records.Record: A standard implementation of a profile record component.
498 def deserialize_character_records( 499 self, 500 payload: typedefs.JSONObject, 501 scores: typing.Optional[records.RecordScores] = None, 502 record_hashes: typing.Optional[list[int]] = None, 503 ) -> records.CharacterRecord: 504 record = self.deserialize_records(payload, scores) 505 return records.CharacterRecord( 506 scores=scores, 507 categories_node_hash=record.categories_node_hash, 508 seals_node_hash=record.seals_node_hash, 509 state=record.state, 510 objectives=record.objectives, 511 interval_objectives=record.interval_objectives, 512 redeemed_count=payload.get("intervalsRedeemedCount", 0), 513 completion_times=payload.get("completedCount"), 514 reward_visibility=payload.get("rewardVisibility"), 515 record_hashes=record_hashes or [], 516 )
Deserialize a JSON object of a profile character record component.
This almost does the same this as deserialize_records but
has more fields which can only be found in a character record.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON object payload
Returns
aiobungie.records.CharacterRecord: A standard implementation of a profile character record component.
518 def deserialize_character_dye(self, payload: typedefs.JSONObject) -> character.Dye: 519 return character.Dye( 520 channel_hash=payload["channelHash"], dye_hash=payload["dyeHash"] 521 )
Deserialize a JSON payload of a character's dye information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.character.Dye: Information about a character dye object.
523 def deserialize_character_customization( 524 self, payload: typedefs.JSONObject 525 ) -> character.CustomizationOptions: 526 return character.CustomizationOptions( 527 personality=payload["personality"], 528 face=payload["face"], 529 skin_color=payload["skinColor"], 530 lip_color=payload["lipColor"], 531 eye_color=payload["eyeColor"], 532 hair_colors=payload.get("hairColors", []), 533 feature_colors=payload.get("featureColors", []), 534 decal_color=payload["decalColor"], 535 wear_helmet=payload["wearHelmet"], 536 hair_index=payload["hairIndex"], 537 feature_index=payload["featureIndex"], 538 decal_index=payload["decalIndex"], 539 )
Deserialize a JSON payload of a character customization information found in character render data profile component.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.character.CustomizationOptions: Information about a character customs object.
541 def deserialize_character_minimal_equipments( 542 self, payload: typedefs.JSONObject 543 ) -> character.MinimalEquipments: 544 dyes = None 545 if raw_dyes := payload.get("dyes"): 546 if raw_dyes: 547 dyes = [self.deserialize_character_dye(dye) for dye in raw_dyes] 548 return character.MinimalEquipments( 549 net=self._net, item_hash=payload["itemHash"], dyes=dyes 550 )
Deserialize a singular JSON peer view of equipment found in character render data profile component.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.character.MinimalEquipments: A minimal equipment object.
552 def deserialize_character_render_data( 553 self, payload: typedefs.JSONObject, / 554 ) -> character.RenderedData: 555 return character.RenderedData( 556 net=self._net, 557 customization=self.deserialize_character_customization( 558 payload["customization"] 559 ), 560 custom_dyes=[ 561 self.deserialize_character_dye(dye) 562 for dye in payload["customDyes"] 563 if dye 564 ], 565 equipment=[ 566 self.deserialize_character_minimal_equipments(equipment) 567 for equipment in payload["peerView"]["equipment"] 568 ], 569 )
Deserialize a JSON payload of a profile character render data component.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.RenderedData: A character rendered data profile component.
571 def deserialize_available_activity( 572 self, payload: typedefs.JSONObject 573 ) -> activity.AvailableActivity: 574 return activity.AvailableActivity( 575 hash=payload["activityHash"], 576 is_new=payload["isNew"], 577 is_completed=payload["isCompleted"], 578 is_visible=payload["isVisible"], 579 display_level=payload.get("displayLevel"), 580 recommended_light=payload.get("recommendedLight"), 581 difficulty=activity.Difficulty(payload["difficultyTier"]), 582 can_join=payload["canJoin"], 583 can_lead=payload["canLead"], 584 )
Deserialize a JSON payload of an available activities.
This method is used to deserialize an array of aiobungie.crates.CharacterActivity.available_activities.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.AvailableActivity: An available activity object.
586 def deserialize_character_activity( 587 self, payload: typedefs.JSONObject 588 ) -> activity.CharacterActivity: 589 current_mode: typing.Optional[enums.GameMode] = None 590 if raw_current_mode := payload.get("currentActivityModeType"): 591 current_mode = enums.GameMode(raw_current_mode) 592 593 current_mode_types: typing.Optional[collections.Sequence[enums.GameMode]] = None 594 if raw_current_modes := payload.get("currentActivityModeTypes"): 595 current_mode_types = [enums.GameMode(type_) for type_ in raw_current_modes] 596 597 return activity.CharacterActivity( 598 date_started=time.clean_date(payload["dateActivityStarted"]), 599 current_hash=payload["currentActivityHash"], 600 current_mode_hash=payload["currentActivityModeHash"], 601 current_mode=current_mode, 602 current_mode_hashes=payload.get("currentActivityModeHashes"), 603 current_mode_types=current_mode_types, 604 current_playlist_hash=payload.get("currentPlaylistActivityHash"), 605 last_story_hash=payload["lastCompletedStoryHash"], 606 available_activities=[ 607 self.deserialize_available_activity(activity_) 608 for activity_ in payload["availableActivities"] 609 ], 610 )
Deserialize a JSON payload of character activity profile component.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.CharacterActivity: A character activities component object.
612 def deserialize_profile_items( 613 self, payload: typedefs.JSONObject, / 614 ) -> list[profile.ProfileItemImpl]: 615 return [self.deserialize_profile_item(item) for item in payload["items"]]
Deserialize a JSON payload of profile items component information.
This may deserialize profileInventories or profileCurrencies or any
other alternatives.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.ProfileItemImpl]: A profile component object that contains items of the deserialized payload.
658 def deserialize_progressions( 659 self, payload: typedefs.JSONObject 660 ) -> progressions.Progression: 661 return progressions.Progression( 662 hash=int(payload["progressionHash"]), 663 level=int(payload["level"]), 664 cap=int(payload["levelCap"]), 665 daily_limit=int(payload["dailyLimit"]), 666 weekly_limit=int(payload["weeklyLimit"]), 667 current_progress=int(payload["currentProgress"]), 668 daily_progress=int(payload["dailyProgress"]), 669 needed=int(payload["progressToNextLevel"]), 670 next_level=int(payload["nextLevelAt"]), 671 )
758 def deserialize_milestone( 759 self, payload: typedefs.JSONObject 760 ) -> milestones.Milestone: 761 start_date: typing.Optional[datetime.datetime] = None 762 if raw_start_date := payload.get("startDate"): 763 start_date = time.clean_date(raw_start_date) 764 765 end_date: typing.Optional[datetime.datetime] = None 766 if raw_end_date := payload.get("endDate"): 767 end_date = time.clean_date(raw_end_date) 768 769 rewards: typing.Optional[ 770 collections.Collection[milestones.MilestoneReward] 771 ] = None 772 if raw_rewards := payload.get("rewards"): 773 rewards = [ 774 self._deserialize_milestone_rewards(reward) for reward in raw_rewards 775 ] 776 777 activities: typing.Optional[ 778 collections.Sequence[milestones.MilestoneActivity] 779 ] = None 780 if raw_activities := payload.get("activities"): 781 activities = [ 782 self._deserialize_milestone_activity(active) 783 for active in raw_activities 784 ] 785 786 quests: typing.Optional[collections.Sequence[milestones.MilestoneQuest]] = None 787 if raw_quests := payload.get("availableQuests"): 788 quests = [ 789 self._deserialize_milestone_available_quest(quest) 790 for quest in raw_quests 791 ] 792 793 vendors: typing.Optional[ 794 collections.Sequence[milestones.MilestoneVendor] 795 ] = None 796 if raw_vendors := payload.get("vendors"): 797 vendors = [ 798 milestones.MilestoneVendor( 799 vendor_hash=vendor["vendorHash"], 800 preview_itemhash=vendor.get("previewItemHash"), 801 ) 802 for vendor in raw_vendors 803 ] 804 805 return milestones.Milestone( 806 hash=payload["milestoneHash"], 807 start_date=start_date, 808 end_date=end_date, 809 order=payload["order"], 810 rewards=rewards, 811 available_quests=quests, 812 activities=activities, 813 vendors=vendors, 814 )
868 def deserialize_character_progressions( 869 self, payload: typedefs.JSONObject 870 ) -> character.CharacterProgression: 871 progressions_ = { 872 int(prog_id): self.deserialize_progressions(prog) 873 for prog_id, prog in payload["progressions"].items() 874 } 875 876 factions = { 877 int(faction_id): self._deserialize_factions(faction) 878 for faction_id, faction in payload["factions"].items() 879 } 880 881 milestones_ = { 882 int(milestone_hash): self.deserialize_milestone(milestone) 883 for milestone_hash, milestone in payload["milestones"].items() 884 } 885 886 uninstanced_item_objectives = { 887 int(item_hash): [self.deserialize_objectives(ins) for ins in obj] 888 for item_hash, obj in payload["uninstancedItemObjectives"].items() 889 } 890 891 artifact = payload["seasonalArtifact"] 892 seasonal_artifact = season.CharacterScopedArtifact( 893 hash=artifact["artifactHash"], 894 points_used=artifact["pointsUsed"], 895 reset_count=artifact["resetCount"], 896 tiers=[ 897 self._deserialize_artifact_tiers(tier) for tier in artifact["tiers"] 898 ], 899 ) 900 checklists = payload["checklists"] 901 902 return character.CharacterProgression( 903 progressions=progressions_, 904 factions=factions, 905 checklists=checklists, 906 milestones=milestones_, 907 seasonal_artifact=seasonal_artifact, 908 uninstanced_item_objectives=uninstanced_item_objectives, 909 )
911 def deserialize_character_progressions_mapping( 912 self, payload: typedefs.JSONObject 913 ) -> collections.Mapping[int, character.CharacterProgression]: 914 character_progressions: collections.Mapping[ 915 int, character.CharacterProgression 916 ] = {} 917 for char_id, data in payload["data"].items(): 918 # A little hack to stop mypy complaining about Mapping <-> dict 919 character_progressions[ 920 int(char_id) 921 ] = self.deserialize_character_progressions(data) # type: ignore[index] 922 return character_progressions
924 def deserialize_characters_records( 925 self, 926 payload: typedefs.JSONObject, 927 ) -> collections.Mapping[int, records.CharacterRecord]: 928 return { 929 int(rec_id): self.deserialize_character_records( 930 rec, record_hashes=payload.get("featuredRecordHashes") 931 ) 932 for rec_id, rec in payload["records"].items() 933 }
935 def deserialize_profile_records( 936 self, payload: typedefs.JSONObject 937 ) -> collections.Mapping[int, records.Record]: 938 raw_profile_records = payload["data"] 939 scores = records.RecordScores( 940 current_score=raw_profile_records["score"], 941 legacy_score=raw_profile_records["legacyScore"], 942 lifetime_score=raw_profile_records["lifetimeScore"], 943 ) 944 return { 945 int(record_id): self.deserialize_records( 946 record, 947 scores, 948 categories_hash=raw_profile_records["recordCategoriesRootNodeHash"], 949 seals_hash=raw_profile_records["recordSealsRootNodeHash"], 950 ) 951 for record_id, record in raw_profile_records["records"].items() 952 }
987 def deserialize_craftables_component( 988 self, payload: typedefs.JSONObject 989 ) -> components.CraftablesComponent: 990 return components.CraftablesComponent( 991 net=self._net, 992 craftables={ 993 int(item_id): self._deserialize_craftable_item(item) 994 for item_id, item in payload["craftables"].items() 995 if item is not None 996 }, 997 crafting_root_node_hash=payload["craftingRootNodeHash"], 998 )
1000 def deserialize_components( # noqa: C901 Too complex. 1001 self, payload: typedefs.JSONObject 1002 ) -> components.Component: 1003 profile_: typing.Optional[profile.Profile] = None 1004 if raw_profile := payload.get("profile"): 1005 profile_ = self.deserialize_profile(raw_profile) 1006 1007 profile_progression: typing.Optional[profile.ProfileProgression] = None 1008 if raw_profile_progression := payload.get("profileProgression"): 1009 profile_progression = self.deserialize_profile_progression( 1010 raw_profile_progression 1011 ) 1012 1013 profile_currencies: typing.Optional[ 1014 collections.Sequence[profile.ProfileItemImpl] 1015 ] = None 1016 if raw_profile_currencies := payload.get("profileCurrencies"): 1017 if "data" in raw_profile_currencies: 1018 profile_currencies = self.deserialize_profile_items( 1019 raw_profile_currencies["data"] 1020 ) 1021 1022 profile_inventories: typing.Optional[ 1023 collections.Sequence[profile.ProfileItemImpl] 1024 ] = None 1025 if raw_profile_inventories := payload.get("profileInventory"): 1026 if "data" in raw_profile_inventories: 1027 profile_inventories = self.deserialize_profile_items( 1028 raw_profile_inventories["data"] 1029 ) 1030 1031 profile_records: typing.Optional[ 1032 collections.Mapping[int, records.Record] 1033 ] = None 1034 1035 if raw_profile_records_ := payload.get("profileRecords"): 1036 profile_records = self.deserialize_profile_records(raw_profile_records_) 1037 1038 characters: typing.Optional[typing.Mapping[int, character.Character]] = None 1039 if raw_characters := payload.get("characters"): 1040 characters = self.deserialize_characters(raw_characters) 1041 1042 character_records: typing.Optional[ 1043 collections.Mapping[int, records.CharacterRecord] 1044 ] = None 1045 1046 if raw_character_records := payload.get("characterRecords"): 1047 # Had to do it in two steps.. 1048 to_update: typedefs.JSONObject = {} 1049 for _, data in raw_character_records["data"].items(): 1050 for record_id, record in data.items(): 1051 to_update[record_id] = record 1052 1053 character_records = { 1054 int(rec_id): self.deserialize_character_records( 1055 rec, record_hashes=to_update.get("featuredRecordHashes") 1056 ) 1057 for rec_id, rec in to_update["records"].items() 1058 } 1059 1060 character_equipments: typing.Optional[ 1061 collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]] 1062 ] = None 1063 if raw_character_equips := payload.get("characterEquipment"): 1064 character_equipments = self.deserialize_character_equipments( 1065 raw_character_equips 1066 ) 1067 1068 character_inventories: typing.Optional[ 1069 collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]] 1070 ] = None 1071 if raw_character_inventories := payload.get("characterInventories"): 1072 if "data" in raw_character_inventories: 1073 character_inventories = self.deserialize_character_equipments( 1074 raw_character_inventories 1075 ) 1076 1077 character_activities: typing.Optional[ 1078 collections.Mapping[int, activity.CharacterActivity] 1079 ] = None 1080 if raw_char_acts := payload.get("characterActivities"): 1081 character_activities = self.deserialize_character_activities(raw_char_acts) 1082 1083 character_render_data: typing.Optional[ 1084 collections.Mapping[int, character.RenderedData] 1085 ] = None 1086 if raw_character_render_data := payload.get("characterRenderData"): 1087 character_render_data = self.deserialize_characters_render_data( 1088 raw_character_render_data 1089 ) 1090 1091 character_progressions: typing.Optional[ 1092 collections.Mapping[int, character.CharacterProgression] 1093 ] = None 1094 1095 if raw_character_progressions := payload.get("characterProgressions"): 1096 character_progressions = self.deserialize_character_progressions_mapping( 1097 raw_character_progressions 1098 ) 1099 1100 profile_string_vars: typing.Optional[collections.Mapping[int, int]] = None 1101 if raw_profile_string_vars := payload.get("profileStringVariables"): 1102 profile_string_vars = raw_profile_string_vars["data"]["integerValuesByHash"] 1103 1104 character_string_vars: typing.Optional[ 1105 collections.Mapping[int, collections.Mapping[int, int]] 1106 ] = None 1107 if raw_character_string_vars := payload.get("characterStringVariables"): 1108 character_string_vars = { 1109 int(char_id): data["integerValuesByHash"] 1110 for char_id, data in raw_character_string_vars["data"].items() 1111 } 1112 1113 metrics: typing.Optional[ 1114 collections.Sequence[ 1115 collections.Mapping[ 1116 int, tuple[bool, typing.Optional[records.Objective]] 1117 ] 1118 ] 1119 ] = None 1120 root_node_hash: typing.Optional[int] = None 1121 1122 if raw_metrics := payload.get("metrics"): 1123 root_node_hash = raw_metrics["data"]["metricsRootNodeHash"] 1124 metrics = [ 1125 { 1126 int(metrics_hash): ( 1127 data["invisible"], 1128 self.deserialize_objectives(data["objectiveProgress"]) 1129 if "objectiveProgress" in data 1130 else None, 1131 ) 1132 for metrics_hash, data in raw_metrics["data"]["metrics"].items() 1133 } 1134 ] 1135 transitory: typing.Optional[fireteams.FireteamParty] = None 1136 if raw_transitory := payload.get("profileTransitoryData"): 1137 if "data" in raw_transitory: 1138 transitory = self.deserialize_fireteam_party(raw_transitory["data"]) 1139 1140 item_components: typing.Optional[components.ItemsComponent] = None 1141 if raw_item_components := payload.get("itemComponents"): 1142 item_components = self.deserialize_items_component(raw_item_components) 1143 1144 profile_plugsets: typing.Optional[ 1145 collections.Mapping[int, collections.Sequence[items.PlugItemState]] 1146 ] = None 1147 1148 if raw_profile_plugs := payload.get("profilePlugSets"): 1149 profile_plugsets = { 1150 int(index): [self.deserialize_plug_item_state(state) for state in data] 1151 for index, data in raw_profile_plugs["data"]["plugs"].items() 1152 } 1153 1154 character_plugsets: typing.Optional[ 1155 collections.Mapping[ 1156 int, collections.Mapping[int, collections.Sequence[items.PlugItemState]] 1157 ] 1158 ] = None 1159 if raw_char_plugsets := payload.get("characterPlugSets"): 1160 character_plugsets = { 1161 int(char_id): { 1162 int(index): [ 1163 self.deserialize_plug_item_state(state) for state in data 1164 ] 1165 for index, data in inner["plugs"].items() 1166 } 1167 for char_id, inner in raw_char_plugsets["data"].items() 1168 } 1169 1170 character_collectibles: typing.Optional[ 1171 collections.Mapping[int, items.Collectible] 1172 ] = None 1173 if raw_character_collectibles := payload.get("characterCollectibles"): 1174 character_collectibles = { 1175 int(char_id): self._deserialize_collectible(data) 1176 for char_id, data in raw_character_collectibles["data"].items() 1177 } 1178 1179 profile_collectibles: typing.Optional[items.Collectible] = None 1180 if raw_profile_collectibles := payload.get("profileCollectibles"): 1181 profile_collectibles = self._deserialize_collectible( 1182 raw_profile_collectibles["data"] 1183 ) 1184 1185 profile_nodes: typing.Optional[collections.Mapping[int, records.Node]] = None 1186 if raw_profile_nodes := payload.get("profilePresentationNodes"): 1187 profile_nodes = { 1188 int(node_hash): self._deserialize_node(node) 1189 for node_hash, node in raw_profile_nodes["data"]["nodes"].items() 1190 } 1191 1192 character_nodes: typing.Optional[ 1193 collections.Mapping[int, collections.Mapping[int, records.Node]] 1194 ] = None 1195 if raw_character_nodes := payload.get("characterPresentationNodes"): 1196 character_nodes = { 1197 int(char_id): { 1198 int(node_hash): self._deserialize_node(node) 1199 for node_hash, node in each_character["nodes"].items() 1200 } 1201 for char_id, each_character in raw_character_nodes["data"].items() 1202 } 1203 1204 platform_silver: typing.Optional[ 1205 collections.Mapping[str, profile.ProfileItemImpl] 1206 ] = None 1207 if raw_platform_silver := payload.get("platformSilver"): 1208 if "data" in raw_platform_silver: 1209 platform_silver = { 1210 platform_name: self.deserialize_profile_item(item) 1211 for platform_name, item in raw_platform_silver["data"][ 1212 "platformSilver" 1213 ].items() 1214 } 1215 1216 character_currency_lookups: typing.Optional[ 1217 collections.Mapping[int, collections.Sequence[items.Currency]] 1218 ] = None 1219 if raw_char_lookups := payload.get("characterCurrencyLookups"): 1220 if "data" in raw_char_lookups: 1221 character_currency_lookups = { 1222 int(char_id): self._deserialize_currencies(currency) 1223 for char_id, currency in raw_char_lookups["data"].items() 1224 } 1225 1226 character_craftables: typing.Optional[ 1227 collections.Mapping[int, components.CraftablesComponent] 1228 ] = None 1229 if raw_character_craftables := payload.get("characterCraftables"): 1230 if "data" in raw_character_craftables: 1231 character_craftables = { 1232 int(char_id): self.deserialize_craftables_component(craftable) 1233 for char_id, craftable in raw_character_craftables["data"].items() 1234 } 1235 1236 return components.Component( 1237 profiles=profile_, 1238 profile_progression=profile_progression, 1239 profile_currencies=profile_currencies, 1240 profile_inventories=profile_inventories, 1241 profile_records=profile_records, 1242 characters=characters, 1243 character_records=character_records, 1244 character_equipments=character_equipments, 1245 character_inventories=character_inventories, 1246 character_activities=character_activities, 1247 character_render_data=character_render_data, 1248 character_progressions=character_progressions, 1249 profile_string_variables=profile_string_vars, 1250 character_string_variables=character_string_vars, 1251 metrics=metrics, 1252 root_node_hash=root_node_hash, 1253 transitory=transitory, 1254 item_components=item_components, 1255 profile_plugsets=profile_plugsets, 1256 character_plugsets=character_plugsets, 1257 character_collectibles=character_collectibles, 1258 profile_collectibles=profile_collectibles, 1259 profile_nodes=profile_nodes, 1260 character_nodes=character_nodes, 1261 platform_silver=platform_silver, 1262 character_currency_lookups=character_currency_lookups, 1263 character_craftables=character_craftables, 1264 )
Deserialize a JSON payload of Bungie.net profile components information.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
aiobungie.crates.Component: A component implementation that includes all other components of the deserialized payload.
1266 def deserialize_items_component( 1267 self, payload: typedefs.JSONObject 1268 ) -> components.ItemsComponent: 1269 instances: typing.Optional[ 1270 collections.Sequence[collections.Mapping[int, items.ItemInstance]] 1271 ] = None 1272 if raw_instances := payload.get("instances"): 1273 instances = [ 1274 { 1275 int(ins_id): self.deserialize_instanced_item(item) 1276 for ins_id, item in raw_instances["data"].items() 1277 } 1278 ] 1279 1280 render_data: typing.Optional[ 1281 collections.Mapping[int, tuple[bool, dict[int, int]]] 1282 ] = None 1283 if raw_render_data := payload.get("renderData"): 1284 render_data = { 1285 int(ins_id): (data["useCustomDyes"], data["artRegions"]) 1286 for ins_id, data in raw_render_data["data"].items() 1287 } 1288 1289 stats: typing.Optional[collections.Mapping[int, items.ItemStatsView]] = None 1290 if raw_stats := payload.get("stats"): 1291 builder: collections.Mapping[int, items.ItemStatsView] = {} 1292 for ins_id, stat in raw_stats["data"].items(): 1293 for _, items_ in stat.items(): 1294 builder[int(ins_id)] = self.deserialize_item_stats_view(items_) # type: ignore[index] 1295 stats = builder 1296 1297 sockets: typing.Optional[ 1298 collections.Mapping[int, collections.Sequence[items.ItemSocket]] 1299 ] = None 1300 if raw_sockets := payload.get("sockets"): 1301 sockets = { 1302 int(ins_id): [ 1303 self.deserialize_item_socket(socket) for socket in item["sockets"] 1304 ] 1305 for ins_id, item in raw_sockets["data"].items() 1306 } 1307 1308 objectives: typing.Optional[ 1309 collections.Mapping[int, collections.Sequence[records.Objective]] 1310 ] = None 1311 if raw_objectives := payload.get("objectives"): 1312 objectives = { 1313 int(ins_id): [self.deserialize_objectives(objective)] 1314 for ins_id, data in raw_objectives["data"].items() 1315 for objective in data["objectives"] 1316 } 1317 1318 perks: typing.Optional[ 1319 collections.Mapping[int, collections.Collection[items.ItemPerk]] 1320 ] = None 1321 if raw_perks := payload.get("perks"): 1322 perks = { 1323 int(ins_id): [ 1324 self.deserialize_item_perk(perk) for perk in item["perks"] 1325 ] 1326 for ins_id, item in raw_perks["data"].items() 1327 } 1328 1329 plug_states: typing.Optional[collections.Sequence[items.PlugItemState]] = None 1330 if raw_plug_states := payload.get("plugStates"): 1331 pending_states: list[items.PlugItemState] = [] 1332 for _, plug in raw_plug_states["data"].items(): 1333 pending_states.append(self.deserialize_plug_item_state(plug)) 1334 plug_states = pending_states 1335 1336 reusable_plugs: typing.Optional[ 1337 collections.Mapping[int, collections.Sequence[items.PlugItemState]] 1338 ] = None 1339 if raw_re_plugs := payload.get("reusablePlugs"): 1340 reusable_plugs = { 1341 int(ins_id): [ 1342 self.deserialize_plug_item_state(state) for state in inner 1343 ] 1344 for ins_id, plug in raw_re_plugs["data"].items() 1345 for inner in list(plug["plugs"].values()) 1346 } 1347 1348 plug_objectives: typing.Optional[ 1349 collections.Mapping[ 1350 int, collections.Mapping[int, collections.Collection[records.Objective]] 1351 ] 1352 ] = None 1353 if raw_plug_objectives := payload.get("plugObjectives"): 1354 plug_objectives = { 1355 int(ins_id): { 1356 int(obj_hash): [self.deserialize_objectives(obj) for obj in objs] 1357 for obj_hash, objs in inner["objectivesPerPlug"].items() 1358 } 1359 for ins_id, inner in raw_plug_objectives["data"].items() 1360 } 1361 1362 return components.ItemsComponent( 1363 sockets=sockets, 1364 stats=stats, 1365 render_data=render_data, 1366 instances=instances, 1367 objectives=objectives, 1368 perks=perks, 1369 plug_states=plug_states, 1370 reusable_plugs=reusable_plugs, 1371 plug_objectives=plug_objectives, 1372 )
Deserialize a JSON objects within the itemComponents key.`
1374 def deserialize_character_component( # type: ignore[call-arg] 1375 self, payload: typedefs.JSONObject 1376 ) -> components.CharacterComponent: 1377 character_: typing.Optional[character.Character] = None 1378 if raw_singular_character := payload.get("character"): 1379 character_ = self.deserialize_character(raw_singular_character["data"]) 1380 1381 inventory: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None 1382 if raw_inventory := payload.get("inventory"): 1383 if "data" in raw_inventory: 1384 inventory = self.deserialize_profile_items(raw_inventory["data"]) 1385 1386 activities: typing.Optional[activity.CharacterActivity] = None 1387 if raw_activities := payload.get("activities"): 1388 activities = self.deserialize_character_activity(raw_activities["data"]) 1389 1390 equipment: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None 1391 if raw_equipments := payload.get("equipment"): 1392 equipment = self.deserialize_profile_items(raw_equipments["data"]) 1393 1394 progressions_: typing.Optional[character.CharacterProgression] = None 1395 if raw_progressions := payload.get("progressions"): 1396 progressions_ = self.deserialize_character_progressions( 1397 raw_progressions["data"] 1398 ) 1399 1400 render_data: typing.Optional[character.RenderedData] = None 1401 if raw_render_data := payload.get("renderData"): 1402 render_data = self.deserialize_character_render_data( 1403 raw_render_data["data"] 1404 ) 1405 1406 character_records: typing.Optional[ 1407 collections.Mapping[int, records.CharacterRecord] 1408 ] = None 1409 if raw_char_records := payload.get("records"): 1410 character_records = self.deserialize_characters_records( 1411 raw_char_records["data"] 1412 ) 1413 1414 item_components: typing.Optional[components.ItemsComponent] = None 1415 if raw_item_components := payload.get("itemComponents"): 1416 item_components = self.deserialize_items_component(raw_item_components) 1417 1418 nodes: typing.Optional[collections.Mapping[int, records.Node]] = None 1419 if raw_nodes := payload.get("presentationNodes"): 1420 nodes = { 1421 int(node_hash): self._deserialize_node(node) 1422 for node_hash, node in raw_nodes["data"]["nodes"].items() 1423 } 1424 1425 collectibles: typing.Optional[items.Collectible] = None 1426 if raw_collectibles := payload.get("collectibles"): 1427 collectibles = self._deserialize_collectible(raw_collectibles["data"]) 1428 1429 currency_lookups: typing.Optional[collections.Sequence[items.Currency]] = None 1430 if raw_currencies := payload.get("currencyLookups"): 1431 if "data" in raw_currencies: 1432 currency_lookups = self._deserialize_currencies(raw_currencies) 1433 1434 return components.CharacterComponent( 1435 activities=activities, 1436 equipment=equipment, 1437 inventory=inventory, 1438 progressions=progressions_, 1439 render_data=render_data, 1440 character=character_, 1441 character_records=character_records, 1442 profile_records=None, 1443 item_components=item_components, 1444 currency_lookups=currency_lookups, 1445 collectibles=collectibles, 1446 nodes=nodes, 1447 )
Deserialize a JSON payload of Destiny 2 character component.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.CharacterComponent: A character component.
1474 def deserialize_inventory_results( 1475 self, payload: typedefs.JSONObject 1476 ) -> iterators.Iterator[entity.SearchableEntity]: 1477 suggested_words: list[str] = payload["suggestedWords"] 1478 1479 def _check_unknown(s: str) -> undefined.UndefinedOr[str]: 1480 return s if not typedefs.is_unknown(s) else undefined.UNDEFINED 1481 1482 return iterators.Iterator( 1483 [ 1484 entity.SearchableEntity( 1485 net=self._net, 1486 hash=data["hash"], 1487 entity_type=data["entityType"], 1488 weight=data["weight"], 1489 suggested_words=suggested_words, 1490 name=data["displayProperties"]["name"], 1491 has_icon=data["displayProperties"]["hasIcon"], 1492 description=_check_unknown( 1493 data["displayProperties"]["description"] 1494 ), 1495 icon=assets.Image(data["displayProperties"]["icon"]), 1496 ) 1497 for data in payload["results"]["results"] 1498 ] 1499 )
Deserialize results of searched Destiny2 entities.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.iterators.Iterator[aiobungie.crates.SearchableEntity]: An iterator over the found searched entities.
1528 def deserialize_inventory_entity( # noqa: C901 Too complex. 1529 self, payload: typedefs.JSONObject, / 1530 ) -> entity.InventoryEntity: 1531 props = self._set_entity_attrs(payload) 1532 objects = self._deserialize_inventory_item_objects(payload) 1533 1534 collectible_hash: typing.Optional[int] = None 1535 if raw_collectible_hash := payload.get("collectibleHash"): 1536 collectible_hash = int(raw_collectible_hash) 1537 1538 secondary_icon: undefined.UndefinedOr[assets.Image] = undefined.UNDEFINED 1539 if raw_second_icon := payload.get("secondaryIcon"): 1540 secondary_icon = assets.Image(raw_second_icon) 1541 1542 secondary_overlay: undefined.UndefinedOr[assets.Image] = undefined.UNDEFINED 1543 if raw_second_overlay := payload.get("secondaryOverlay"): 1544 secondary_overlay = assets.Image(raw_second_overlay) 1545 1546 secondary_special: undefined.UndefinedOr[assets.Image] = undefined.UNDEFINED 1547 if raw_second_special := payload.get("secondarySpecial"): 1548 secondary_special = assets.Image(raw_second_special) 1549 1550 screenshot: undefined.UndefinedOr[assets.Image] = undefined.UNDEFINED 1551 if raw_screenshot := payload.get("screenshot"): 1552 screenshot = assets.Image(raw_screenshot) 1553 1554 watermark_icon: typing.Optional[assets.Image] = None 1555 if raw_watermark_icon := payload.get("iconWatermark"): 1556 watermark_icon = assets.Image(raw_watermark_icon) 1557 1558 watermark_shelved: typing.Optional[assets.Image] = None 1559 if raw_watermark_shelved := payload.get("iconWatermarkShelved"): 1560 watermark_shelved = assets.Image(raw_watermark_shelved) 1561 1562 about: undefined.UndefinedOr[str] = undefined.UNDEFINED 1563 if (raw_about := payload.get("flavorText")) and not typedefs.is_unknown( 1564 raw_about 1565 ): 1566 about = raw_about 1567 1568 ui_item_style: undefined.UndefinedOr[str] = undefined.UNDEFINED 1569 if ( 1570 raw_ui_style := payload.get("uiItemDisplayStyle") 1571 ) and not typedefs.is_unknown(raw_ui_style): 1572 ui_item_style = raw_ui_style 1573 1574 tier_and_name: undefined.UndefinedOr[str] = undefined.UNDEFINED 1575 if ( 1576 raw_tier_and_name := payload.get("itemTypeAndTierDisplayName") 1577 ) and not typedefs.is_unknown(raw_tier_and_name): 1578 tier_and_name = raw_tier_and_name 1579 1580 type_name: undefined.UndefinedOr[str] = undefined.UNDEFINED 1581 if ( 1582 raw_type_name := payload.get("itemTypeDisplayName") 1583 ) and not typedefs.is_unknown(raw_type_name): 1584 type_name = raw_type_name 1585 1586 display_source: undefined.UndefinedOr[str] = undefined.UNDEFINED 1587 if ( 1588 raw_display_source := payload.get("displaySource") 1589 ) and not typedefs.is_unknown(raw_display_source): 1590 display_source = raw_display_source 1591 1592 lorehash: typing.Optional[int] = None 1593 if raw_lore_hash := payload.get("loreHash"): 1594 lorehash = int(raw_lore_hash) 1595 1596 summary_hash: typing.Optional[int] = None 1597 if raw_summary_hash := payload.get("summaryItemHash"): 1598 summary_hash = raw_summary_hash 1599 1600 breaker_type_hash: typing.Optional[int] = None 1601 if raw_breaker_type_hash := payload.get("breakerTypeHash"): 1602 breaker_type_hash = int(raw_breaker_type_hash) 1603 1604 damage_types: typing.Optional[collections.Sequence[int]] = None 1605 if raw_damage_types := payload.get("damageTypes"): 1606 damage_types = [int(type_) for type_ in raw_damage_types] 1607 1608 damagetype_hashes: typing.Optional[collections.Sequence[int]] = None 1609 if raw_damagetype_hashes := payload.get("damageTypeHashes"): 1610 damagetype_hashes = [int(type_) for type_ in raw_damagetype_hashes] 1611 1612 default_damagetype_hash: typing.Optional[int] = None 1613 if raw_defaultdmg_hash := payload.get("defaultDamageTypeHash"): 1614 default_damagetype_hash = int(raw_defaultdmg_hash) 1615 1616 emblem_objective_hash: typing.Optional[int] = None 1617 if raw_emblem_obj_hash := payload.get("emblemObjectiveHash"): 1618 emblem_objective_hash = int(raw_emblem_obj_hash) 1619 1620 tier_type: typing.Optional[enums.TierType] = None 1621 tier: typing.Optional[enums.ItemTier] = None 1622 bucket_hash: typing.Optional[int] = None 1623 recovery_hash: typing.Optional[int] = None 1624 tier_name: undefined.UndefinedOr[str] = undefined.UNDEFINED 1625 isinstance_item: bool = False 1626 expire_tool_tip: undefined.UndefinedOr[str] = undefined.UNDEFINED 1627 expire_in_orbit_message: undefined.UndefinedOr[str] = undefined.UNDEFINED 1628 suppress_expiration: bool = False 1629 max_stack_size: typing.Optional[int] = None 1630 stack_label: undefined.UndefinedOr[str] = undefined.UNDEFINED 1631 1632 if inventory := payload.get("inventory"): 1633 tier_type = enums.TierType(int(inventory["tierType"])) 1634 tier = enums.ItemTier(int(inventory["tierTypeHash"])) 1635 bucket_hash = int(inventory["bucketTypeHash"]) 1636 recovery_hash = int(inventory["recoveryBucketTypeHash"]) 1637 tier_name = inventory["tierTypeName"] 1638 isinstance_item = inventory["isInstanceItem"] 1639 suppress_expiration = inventory["suppressExpirationWhenObjectivesComplete"] 1640 max_stack_size = int(inventory["maxStackSize"]) 1641 1642 try: 1643 stack_label = inventory["stackUniqueLabel"] 1644 except KeyError: 1645 pass 1646 1647 return entity.InventoryEntity( 1648 net=self._net, 1649 collectible_hash=collectible_hash, 1650 name=props.name, 1651 about=about, 1652 emblem_objective_hash=emblem_objective_hash, 1653 suppress_expiration=suppress_expiration, 1654 max_stack_size=max_stack_size, 1655 stack_label=stack_label, 1656 tier=tier, 1657 tier_type=tier_type, 1658 tier_name=tier_name, 1659 bucket_hash=bucket_hash, 1660 recovery_bucket_hash=recovery_hash, 1661 isinstance_item=isinstance_item, 1662 expire_in_orbit_message=expire_in_orbit_message, 1663 expiration_tooltip=expire_tool_tip, 1664 lore_hash=lorehash, 1665 type_and_tier_name=tier_and_name, 1666 summary_hash=summary_hash, 1667 ui_display_style=ui_item_style, 1668 type_name=type_name, 1669 breaker_type_hash=breaker_type_hash, 1670 description=props.description, 1671 display_source=display_source, 1672 hash=props.hash, 1673 damage_types=damage_types, 1674 index=props.index, 1675 icon=props.icon, 1676 has_icon=props.has_icon, 1677 screenshot=screenshot, 1678 watermark_icon=watermark_icon, 1679 watermark_shelved=watermark_shelved, 1680 secondary_icon=secondary_icon, 1681 secondary_overlay=secondary_overlay, 1682 secondary_special=secondary_special, 1683 type=enums.ItemType(int(payload["itemType"])), 1684 trait_hashes=[int(id_) for id_ in payload.get("traitHashes", [])], 1685 trait_ids=[trait for trait in payload.get("traitIds", [])], 1686 category_hashes=[int(hash_) for hash_ in payload["itemCategoryHashes"]], 1687 item_class=enums.Class(int(payload["classType"])), 1688 sub_type=enums.ItemSubType(int(payload["itemSubType"])), 1689 breaker_type=int(payload["breakerType"]), 1690 default_damagetype=int(payload["defaultDamageType"]), 1691 default_damagetype_hash=default_damagetype_hash, 1692 damagetype_hashes=damagetype_hashes, 1693 tooltip_notifications=payload["tooltipNotifications"], 1694 not_transferable=payload["nonTransferrable"], 1695 allow_actions=payload["allowActions"], 1696 is_equippable=payload["equippable"], 1697 objects=objects, 1698 background_colors=payload.get("backgroundColor", {}), 1699 season_hash=payload.get("seasonHash"), 1700 has_postmaster_effect=payload["doesPostmasterPullHaveSideEffects"], 1701 )
Deserialize a JSON payload of an inventory entity item information.
This can be any item from DestinyInventoryItemDefinition definition.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.InventoryEntity: An entity item.
1703 def deserialize_objective_entity( 1704 self, payload: typedefs.JSONObject, / 1705 ) -> entity.ObjectiveEntity: 1706 props = self._set_entity_attrs(payload) 1707 return entity.ObjectiveEntity( 1708 net=self._net, 1709 hash=props.hash, 1710 index=props.index, 1711 description=props.description, 1712 name=props.name, 1713 has_icon=props.has_icon, 1714 icon=props.icon, 1715 unlock_value_hash=payload["unlockValueHash"], 1716 completion_value=payload["completionValue"], 1717 scope=entity.GatingScope(int(payload["scope"])), 1718 location_hash=payload["locationHash"], 1719 allowed_negative_value=payload["allowNegativeValue"], 1720 allowed_value_change=payload["allowValueChangeWhenCompleted"], 1721 counting_downward=payload["isCountingDownward"], 1722 value_style=entity.ValueUIStyle(int(payload["valueStyle"])), 1723 progress_description=payload["progressDescription"], 1724 perks=payload["perks"], 1725 stats=payload["stats"], 1726 minimum_visibility=payload["minimumVisibilityThreshold"], 1727 allow_over_completion=payload["allowOvercompletion"], 1728 show_value_style=payload["showValueOnComplete"], 1729 display_only_objective=payload["isDisplayOnlyObjective"], 1730 complete_value_style=entity.ValueUIStyle( 1731 int(payload["completedValueStyle"]) 1732 ), 1733 progress_value_style=entity.ValueUIStyle( 1734 int(payload["inProgressValueStyle"]) 1735 ), 1736 ui_label=payload["uiLabel"], 1737 ui_style=entity.ObjectiveUIStyle(int(payload["uiStyle"])), 1738 )
Deserialize a JSON payload of an objective entity information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.ObjectiveEntity: An objective entity.
1766 def deserialize_activity( 1767 self, 1768 payload: typedefs.JSONObject, 1769 /, 1770 ) -> activity.Activity: 1771 period = time.clean_date(payload["period"]) 1772 details = payload["activityDetails"] 1773 ref_id = int(details["referenceId"]) 1774 instance_id = int(details["instanceId"]) 1775 mode = enums.GameMode(details["mode"]) 1776 modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]] 1777 is_private = details["isPrivate"] 1778 membership_type = enums.MembershipType(int(details["membershipType"])) 1779 1780 # Since we're using the same fields for post activity method 1781 # this check is required since post activity doesn't values values 1782 values = self._deserialize_activity_values(payload["values"]) 1783 1784 return activity.Activity( 1785 net=self._net, 1786 hash=ref_id, 1787 instance_id=instance_id, 1788 mode=mode, 1789 modes=modes, 1790 is_private=is_private, 1791 membership_type=membership_type, 1792 occurred_at=period, 1793 values=values, 1794 )
Deserialize a JSON payload of an activity history information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.Activity: An activity.
1796 def deserialize_activities( 1797 self, payload: typedefs.JSONObject 1798 ) -> iterators.Iterator[activity.Activity]: 1799 return iterators.Iterator( 1800 [ 1801 self.deserialize_activity(activity_) 1802 for activity_ in payload["activities"] 1803 ] 1804 )
Deserialize a JSON payload of an array of activity history information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.iterators.Iterator[aiobungie.crates.Activity]: Am iterator over activity objects of the deserialized payload.
1806 def deserialize_extended_weapon_values( 1807 self, payload: typedefs.JSONObject 1808 ) -> activity.ExtendedWeaponValues: 1809 assists: typing.Optional[int] = None 1810 if raw_assists := payload["values"].get("uniqueWeaponAssists"): 1811 assists = raw_assists["basic"]["value"] 1812 assists_damage: typing.Optional[int] = None 1813 1814 if raw_assists_damage := payload["values"].get("uniqueWeaponAssistDamage"): 1815 assists_damage = raw_assists_damage["basic"]["value"] 1816 1817 return activity.ExtendedWeaponValues( 1818 reference_id=int(payload["referenceId"]), 1819 kills=payload["values"]["uniqueWeaponKills"]["basic"]["value"], 1820 precision_kills=payload["values"]["uniqueWeaponPrecisionKills"]["basic"][ 1821 "value" 1822 ], 1823 assists=assists, 1824 assists_damage=assists_damage, 1825 precision_kills_percentage=( 1826 payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"]["value"], 1827 payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"][ 1828 "displayValue" 1829 ], 1830 ), 1831 )
Deserialize values of extended weapons JSON object.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.ExtendedWeaponValues: Information about an extended weapon values.
1854 def deserialize_post_activity_player( 1855 self, payload: typedefs.JSONObject, / 1856 ) -> activity.PostActivityPlayer: 1857 player = payload["player"] 1858 1859 class_hash: typedefs.NoneOr[int] = None 1860 if (class_hash := player.get("classHash")) is not None: 1861 class_hash = class_hash 1862 1863 race_hash: typedefs.NoneOr[int] = None 1864 if (race_hash := player.get("raceHash")) is not None: 1865 race_hash = race_hash 1866 1867 gender_hash: typedefs.NoneOr[int] = None 1868 if (gender_hash := player.get("genderHash")) is not None: 1869 gender_hash = gender_hash 1870 1871 character_class: undefined.UndefinedOr[str] = undefined.UNDEFINED 1872 if ( 1873 character_class := player.get("characterClass") 1874 ) and not typedefs.is_unknown(character_class): 1875 character_class = character_class 1876 1877 character_level: typedefs.NoneOr[int] = None 1878 if (character_level := player.get("characterLevel")) is not None: 1879 character_level = character_level 1880 1881 return activity.PostActivityPlayer( 1882 standing=int(payload["standing"]), 1883 score=int(payload["score"]["basic"]["value"]), 1884 character_id=payload["characterId"], 1885 destiny_user=self.deserialize_destiny_membership(player["destinyUserInfo"]), 1886 character_class=character_class, 1887 character_level=character_level, 1888 race_hash=race_hash, 1889 gender_hash=gender_hash, 1890 class_hash=class_hash, 1891 light_level=int(player["lightLevel"]), 1892 emblem_hash=int(player["emblemHash"]), 1893 values=self._deserialize_activity_values(payload["values"]), 1894 extended_values=self._deserialize_extended_values(payload["extended"]), 1895 )
Deserialize a JSON payload of a post activity player information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.PostActivityPlayer: A post activity player object.
1907 def deserialize_post_activity( 1908 self, payload: typedefs.JSONObject 1909 ) -> activity.PostActivity: 1910 period = time.clean_date(payload["period"]) 1911 details = payload["activityDetails"] 1912 ref_id = int(details["referenceId"]) 1913 instance_id = int(details["instanceId"]) 1914 mode = enums.GameMode(details["mode"]) 1915 modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]] 1916 is_private = details["isPrivate"] 1917 membership_type = enums.MembershipType(int(details["membershipType"])) 1918 return activity.PostActivity( 1919 net=self._net, 1920 hash=ref_id, 1921 membership_type=membership_type, 1922 instance_id=instance_id, 1923 mode=mode, 1924 modes=modes, 1925 is_private=is_private, 1926 occurred_at=period, 1927 starting_phase=int(payload["startingPhaseIndex"]), 1928 players=[ 1929 self.deserialize_post_activity_player(player) 1930 for player in payload["entries"] 1931 ], 1932 teams=[ 1933 self._deserialize_post_activity_team(team) for team in payload["teams"] 1934 ], 1935 )
Deserialize a JSON payload of a post activity information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.PostActivity: A post activity object.
1973 def deserialize_aggregated_activity( 1974 self, payload: typedefs.JSONObject 1975 ) -> activity.AggregatedActivity: 1976 return activity.AggregatedActivity( 1977 hash=int(payload["activityHash"]), 1978 values=self._deserialize_aggregated_activity_values(payload["values"]), 1979 )
Deserialize a JSON payload of an aggregated activity.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.AggregatedActivity: An aggregated activity object.
1981 def deserialize_aggregated_activities( 1982 self, payload: typedefs.JSONObject 1983 ) -> iterators.Iterator[activity.AggregatedActivity]: 1984 return iterators.Iterator( 1985 [ 1986 self.deserialize_aggregated_activity(activity) 1987 for activity in payload["activities"] 1988 ] 1989 )
Deserialize a JSON payload of an array of aggregated activities.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.iterators.Iterator[aiobungie.crates.AggregatedActivity]: An iterator over aggregated activities objects.
1991 def deserialize_linked_profiles( 1992 self, payload: typedefs.JSONObject 1993 ) -> profile.LinkedProfile: 1994 bungie_user = self.deserialize_partial_bungie_user(payload["bnetMembership"]) 1995 error_profiles_vec: typing.MutableSequence[user.DestinyMembership] = [] 1996 profiles_vec: typing.MutableSequence[user.DestinyMembership] = [] 1997 1998 if raw_profile := payload.get("profiles"): 1999 for pfile in raw_profile: 2000 profiles_vec.append(self.deserialize_destiny_membership(pfile)) 2001 2002 if raw_profiles_with_errors := payload.get("profilesWithErrors"): 2003 for raw_error_pfile in raw_profiles_with_errors: 2004 if error_pfile := raw_error_pfile.get("infoCard"): 2005 error_profiles_vec.append( 2006 self.deserialize_destiny_membership(error_pfile) 2007 ) 2008 2009 return profile.LinkedProfile( 2010 bungie=bungie_user, 2011 profiles=profiles_vec, 2012 profiles_with_errors=error_profiles_vec, 2013 )
Deserialize a JSON payload of Bungie.net hard linked profile information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.LinkedProfile: A hard linked profile.
2029 def deserialize_public_milestone_content( 2030 self, payload: typedefs.JSONObject 2031 ) -> milestones.MilestoneContent: 2032 items_categoris: typedefs.NoneOr[milestones.MilestoneItems] = None 2033 if raw_categories := payload.get("itemCategories"): 2034 for item in raw_categories: 2035 title = undefined.UNDEFINED 2036 if raw_title := item.get("title"): 2037 if raw_title != typedefs.Unknown: 2038 title = raw_title 2039 if raw_hashes := item.get("itemHashes"): 2040 hashes: collections.Sequence[int] = raw_hashes 2041 2042 items_categoris = milestones.MilestoneItems(title=title, hashes=hashes) 2043 2044 about = undefined.UNDEFINED 2045 if (raw_about := payload["about"]) != typedefs.Unknown: 2046 about = raw_about 2047 2048 status = undefined.UNDEFINED 2049 if (raw_status := payload["status"]) != typedefs.Unknown: 2050 status = raw_status 2051 2052 tips: typing.MutableSequence[undefined.UndefinedOr[str]] = [] 2053 if raw_tips := payload.get("tips"): 2054 for raw_tip in raw_tips: 2055 if raw_tip == typedefs.Unknown: 2056 raw_tip = undefined.UNDEFINED 2057 tips.append(raw_tip) 2058 2059 return milestones.MilestoneContent( 2060 about=about, status=status, tips=tips, items=items_categoris 2061 )
Deserialize a JSON payload of milestone content information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.MilestoneContent: A milestone content.
2063 def deserialize_friend(self, payload: typedefs.JSONObject, /) -> friends.Friend: 2064 name = undefined.UNDEFINED 2065 if (raw_name := payload["bungieGlobalDisplayName"]) != typedefs.Unknown: 2066 name = raw_name 2067 2068 bungie_user: typedefs.NoneOr[user.BungieUser] = None 2069 2070 if raw_bungie_user := payload.get("bungieNetUser"): 2071 bungie_user = self.deserialize_bungie_user(raw_bungie_user) 2072 2073 return friends.Friend( 2074 net=self._net, 2075 id=int(payload["lastSeenAsMembershipId"]), 2076 name=name, 2077 code=payload.get("bungieGlobalDisplayNameCode"), 2078 relationship=enums.Relationship(payload["relationship"]), 2079 user=bungie_user, 2080 online_status=enums.Presence(payload["onlineStatus"]), 2081 online_title=payload["onlineTitle"], 2082 type=enums.MembershipType(payload["lastSeenAsBungieMembershipType"]), 2083 )
Deserialize a JSON payload of a Bungie friend information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.Friend: A friend.
2085 def deserialize_friends( 2086 self, payload: typedefs.JSONObject 2087 ) -> collections.Sequence[friends.Friend]: 2088 mut_seq: typing.MutableSequence[friends.Friend] = [] 2089 if raw_friends := payload.get("friends"): 2090 for friend in raw_friends: 2091 mut_seq.append(self.deserialize_friend(friend)) 2092 return mut_seq
Deserialize a JSON sequence of Bungie friends information.
This is usually used to deserialize the incoming/outgoing friend requests.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.Friend]: A sequence of friends.
2094 def deserialize_friend_requests( 2095 self, payload: typedefs.JSONObject 2096 ) -> friends.FriendRequestView: 2097 incoming: typing.MutableSequence[friends.Friend] = [] 2098 outgoing: typing.MutableSequence[friends.Friend] = [] 2099 2100 if raw_incoming_requests := payload.get("incomingRequests"): 2101 for incoming_request in raw_incoming_requests: 2102 incoming.append(self.deserialize_friend(incoming_request)) 2103 2104 if raw_outgoing_requests := payload.get("outgoingRequests"): 2105 for outgoing_request in raw_outgoing_requests: 2106 outgoing.append(self.deserialize_friend(outgoing_request)) 2107 2108 return friends.FriendRequestView(incoming=incoming, outgoing=outgoing)
Deserialize a JSON sequence of Bungie friend requests information.
This is used for incoming/outgoing friend requests.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.FriendRequestView]: A sequence of incoming and outgoing friends.
2133 def deserialize_fireteams( 2134 self, payload: typedefs.JSONObject 2135 ) -> typedefs.NoneOr[collections.Sequence[fireteams.Fireteam]]: 2136 fireteams_: typing.MutableSequence[fireteams.Fireteam] = [] 2137 2138 result: list[typedefs.JSONObject] 2139 if not (result := payload["results"]): 2140 return None 2141 for elem in result: 2142 fireteams_.append( 2143 self._set_fireteam_fields( 2144 elem, total_results=int(payload["totalResults"]) 2145 ) 2146 ) 2147 return fireteams_
Deserialize a JSON sequence of Bungie fireteams information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.Fireteam]: A sequence of fireteam.
2149 def deserialize_fireteam_destiny_users( 2150 self, payload: typedefs.JSONObject 2151 ) -> fireteams.FireteamUser: 2152 destiny_obj = self.deserialize_destiny_membership(payload) 2153 # We could helpers.just return a DestinyMembership object but this is 2154 # missing the fireteam display name and id fields. 2155 return fireteams.FireteamUser( 2156 net=self._net, 2157 id=destiny_obj.id, 2158 code=destiny_obj.code, 2159 icon=destiny_obj.icon, 2160 types=destiny_obj.types, 2161 type=destiny_obj.type, 2162 is_public=destiny_obj.is_public, 2163 crossave_override=destiny_obj.crossave_override, 2164 name=destiny_obj.name, 2165 last_seen_name=destiny_obj.last_seen_name, 2166 fireteam_display_name=payload["FireteamDisplayName"], 2167 fireteam_membership_id=enums.MembershipType( 2168 payload["FireteamMembershipType"] 2169 ), 2170 )
Deserialize a JSON payload of Bungie fireteam destiny users information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.FireteamUser: A fireteam user.
2172 def deserialize_fireteam_members( 2173 self, payload: typedefs.JSONObject, *, alternatives: bool = False 2174 ) -> collections.Sequence[fireteams.FireteamMember]: 2175 members_: list[fireteams.FireteamMember] = [] 2176 if members := payload.get("Members" if not alternatives else "Alternates"): 2177 for member in members: 2178 bungie_fields = self.deserialize_partial_bungie_user(member) 2179 members_fields = fireteams.FireteamMember( 2180 destiny_user=self.deserialize_fireteam_destiny_users(member), 2181 has_microphone=member["hasMicrophone"], 2182 character_id=int(member["characterId"]), 2183 date_joined=time.clean_date(member["dateJoined"]), 2184 last_platform_invite_date=time.clean_date( 2185 member["lastPlatformInviteAttemptDate"] 2186 ), 2187 last_platform_invite_result=int( 2188 member["lastPlatformInviteAttemptResult"] 2189 ), 2190 net=self._net, 2191 name=bungie_fields.name, 2192 id=bungie_fields.id, 2193 icon=bungie_fields.icon, 2194 is_public=bungie_fields.is_public, 2195 crossave_override=bungie_fields.crossave_override, 2196 types=bungie_fields.types, 2197 type=bungie_fields.type, 2198 ) 2199 members_.append(members_fields) 2200 return members_
Deserialize a JSON sequence of Bungie fireteam members information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload. - alternatives (
bool): If set toTrue, Then it will deserialize thealternativesdata in the payload. If not the it will just deserialize themembersdata.
Returns
collections.Sequence[aiobungie.crates.FireteamUser]: A sequence of the fireteam members.
2203 def deserialize_available_fireteams( 2204 self, 2205 data: typedefs.JSONObject, 2206 *, 2207 no_results: bool = False, 2208 ) -> typing.Union[ 2209 fireteams.AvailableFireteam, collections.Sequence[fireteams.AvailableFireteam] 2210 ]: 2211 fireteams_: list[fireteams.AvailableFireteam] = [] 2212 2213 # This needs to be used outside the results 2214 # JSON key. 2215 if no_results: 2216 payload = data.copy() 2217 2218 if (results := payload.get("results")) is not None: 2219 for fireteam in results: 2220 found_fireteams = self._set_fireteam_fields(fireteam["Summary"]) 2221 fireteams_fields = fireteams.AvailableFireteam( 2222 id=found_fireteams.id, 2223 group_id=found_fireteams.group_id, 2224 platform=found_fireteams.platform, 2225 activity_type=found_fireteams.activity_type, 2226 is_immediate=found_fireteams.is_immediate, 2227 is_public=found_fireteams.is_public, 2228 is_valid=found_fireteams.is_valid, 2229 owner_id=found_fireteams.owner_id, 2230 player_slot_count=found_fireteams.player_slot_count, 2231 available_player_slots=found_fireteams.available_player_slots, 2232 available_alternate_slots=found_fireteams.available_alternate_slots, 2233 title=found_fireteams.title, 2234 date_created=found_fireteams.date_created, 2235 locale=found_fireteams.locale, 2236 last_modified=found_fireteams.last_modified, 2237 total_results=found_fireteams.total_results, 2238 members=self.deserialize_fireteam_members(payload), 2239 alternatives=self.deserialize_fireteam_members( 2240 payload, alternatives=True 2241 ), 2242 ) 2243 if no_results: 2244 return fireteams_fields 2245 else: 2246 fireteams_.append(fireteams_fields) 2247 return fireteams_
Deserialize a JSON payload of a sequence of/fireteam information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload. - no_results (
bool): Whether to deserialize the data fromresultsin the payload or not.
Returns
typing.Union[aiobungie.crates.fireteams.AvailableFireteam, collections.Sequence[aiobungie.crates.fireteams.AvailableFireteam]]# noqa (E501): An available fireteam or a sequence of available fireteam.
2249 def deserialize_fireteam_party( 2250 self, payload: typedefs.JSONObject 2251 ) -> fireteams.FireteamParty: 2252 last_destination_hash: typing.Optional[int] = None 2253 if raw_dest_hash := payload.get("lastOrbitedDestinationHash"): 2254 last_destination_hash = int(raw_dest_hash) 2255 2256 return fireteams.FireteamParty( 2257 members=[ 2258 self._deserialize_fireteam_party_member(member) 2259 for member in payload["partyMembers"] 2260 ], 2261 activity=self._deserialize_fireteam_party_current_activity( 2262 payload["currentActivity"] 2263 ), 2264 settings=self._deserialize_fireteam_party_settings(payload["joinability"]), 2265 last_destination_hash=last_destination_hash, 2266 tracking=payload["tracking"], 2267 )
Deserialize a JSON payload of profileTransitory component response.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.FireteamParty: A fireteam party object of the current fireteam.
2313 def deserialize_seasonal_artifact( 2314 self, payload: typedefs.JSONObject 2315 ) -> season.Artifact: 2316 if raw_artifact := payload.get("seasonalArtifact"): 2317 if points := raw_artifact.get("pointProgression"): 2318 points_prog = progressions.Progression( 2319 hash=points["progressionHash"], 2320 level=points["level"], 2321 cap=points["levelCap"], 2322 daily_limit=points["dailyLimit"], 2323 weekly_limit=points["weeklyLimit"], 2324 current_progress=points["currentProgress"], 2325 daily_progress=points["dailyProgress"], 2326 needed=points["progressToNextLevel"], 2327 next_level=points["nextLevelAt"], 2328 ) 2329 2330 if bonus := raw_artifact.get("powerBonusProgression"): 2331 power_bonus_prog = progressions.Progression( 2332 hash=bonus["progressionHash"], 2333 level=bonus["level"], 2334 cap=bonus["levelCap"], 2335 daily_limit=bonus["dailyLimit"], 2336 weekly_limit=bonus["weeklyLimit"], 2337 current_progress=bonus["currentProgress"], 2338 daily_progress=bonus["dailyProgress"], 2339 needed=bonus["progressToNextLevel"], 2340 next_level=bonus["nextLevelAt"], 2341 ) 2342 artifact = season.Artifact( 2343 hash=raw_artifact["artifactHash"], 2344 power_bonus=raw_artifact["powerBonus"], 2345 acquired_points=raw_artifact["pointsAcquired"], 2346 bonus=power_bonus_prog, 2347 points=points_prog, 2348 ) 2349 return artifact
Deserialize a JSON payload of a Destiny 2 seasonal artifact information.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
aiobungie.crates.Artifact: A seasonal artifact.
2351 def deserialize_profile_progression( 2352 self, payload: typedefs.JSONObject 2353 ) -> profile.ProfileProgression: 2354 return profile.ProfileProgression( 2355 artifact=self.deserialize_seasonal_artifact(payload["data"]), 2356 checklist={ 2357 int(check_id): checklists 2358 for check_id, checklists in payload["data"]["checklists"].items() 2359 }, 2360 )
Deserialize a JSON payload of a profile progression component.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
aiobungie.crates.ProfileProgression: A profile progression component.
2362 def deserialize_instanced_item( 2363 self, payload: typedefs.JSONObject 2364 ) -> items.ItemInstance: 2365 damage_type_hash: typing.Optional[int] = None 2366 if raw_damagetype_hash := payload.get("damageTypeHash"): 2367 damage_type_hash = int(raw_damagetype_hash) 2368 2369 required_hashes: typing.Optional[collections.Collection[int]] = None 2370 if raw_required_hashes := payload.get("unlockHashesRequiredToEquip"): 2371 required_hashes = [int(raw_hash) for raw_hash in raw_required_hashes] 2372 2373 breaker_type: typing.Optional[items.ItemBreakerType] = None 2374 if raw_break_type := payload.get("breakerType"): 2375 breaker_type = items.ItemBreakerType(int(raw_break_type)) 2376 2377 breaker_type_hash: typing.Optional[int] = None 2378 if raw_break_type_hash := payload.get("breakerTypeHash"): 2379 breaker_type_hash = int(raw_break_type_hash) 2380 2381 energy: typing.Optional[items.ItemEnergy] = None 2382 if raw_energy := payload.get("energy"): 2383 energy = self.deserialize_item_energy(raw_energy) 2384 2385 primary_stats = None 2386 if raw_primary_stats := payload.get("primaryStat"): 2387 primary_stats = self.deserialize_item_stats_view(raw_primary_stats) 2388 2389 return items.ItemInstance( 2390 damage_type=enums.DamageType(int(payload["damageType"])), 2391 damage_type_hash=damage_type_hash, 2392 primary_stat=primary_stats, 2393 item_level=int(payload["itemLevel"]), 2394 quality=int(payload["quality"]), 2395 is_equipped=payload["isEquipped"], 2396 can_equip=payload["canEquip"], 2397 equip_required_level=int(payload["equipRequiredLevel"]), 2398 required_equip_unlock_hashes=required_hashes, 2399 cant_equip_reason=int(payload["cannotEquipReason"]), 2400 breaker_type=breaker_type, 2401 breaker_type_hash=breaker_type_hash, 2402 energy=energy, 2403 )
Deserialize a JSON object into an instanced item.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
aiobungie.crates.ItemInstance: An instanced item object.
2405 def deserialize_item_energy(self, payload: typedefs.JSONObject) -> items.ItemEnergy: 2406 energy_hash: typing.Optional[int] = None 2407 if raw_energy_hash := payload.get("energyTypeHash"): 2408 energy_hash = int(raw_energy_hash) 2409 2410 return items.ItemEnergy( 2411 hash=energy_hash, 2412 type=items.ItemEnergyType(int(payload["energyType"])), 2413 capacity=int(payload["energyCapacity"]), 2414 used_energy=int(payload["energyUsed"]), 2415 unused_energy=int(payload["energyUnused"]), 2416 )
2418 def deserialize_item_perk(self, payload: typedefs.JSONObject) -> items.ItemPerk: 2419 perk_hash: typing.Optional[int] = None 2420 if raw_perk_hash := payload.get("perkHash"): 2421 perk_hash = int(raw_perk_hash) 2422 2423 return items.ItemPerk( 2424 hash=perk_hash, 2425 icon=assets.Image(payload["iconPath"]), 2426 is_active=payload["isActive"], 2427 is_visible=payload["visible"], 2428 )
2430 def deserialize_item_socket(self, payload: typedefs.JSONObject) -> items.ItemSocket: 2431 plug_hash: typing.Optional[int] = None 2432 if raw_plug_hash := payload.get("plugHash"): 2433 plug_hash = int(raw_plug_hash) 2434 2435 enable_fail_indexes: typing.Optional[list[int]] = None 2436 if raw_indexes := payload.get("enableFailIndexes"): 2437 enable_fail_indexes = [int(index) for index in raw_indexes] 2438 2439 return items.ItemSocket( 2440 plug_hash=plug_hash, 2441 is_enabled=payload["isEnabled"], 2442 enable_fail_indexes=enable_fail_indexes, 2443 is_visible=payload.get("visible"), 2444 )
2453 def deserialize_plug_item_state( 2454 self, payload: typedefs.JSONObject 2455 ) -> items.PlugItemState: 2456 item_hash: typing.Optional[int] = None 2457 if raw_item_hash := payload.get("plugItemHash"): 2458 item_hash = int(raw_item_hash) 2459 2460 insert_fail_indexes: typedefs.NoneOr[list[int]] = None 2461 if raw_fail_indexes := payload.get("insertFailIndexes"): 2462 insert_fail_indexes = [int(k) for k in raw_fail_indexes] 2463 2464 enable_fail_indexes: typedefs.NoneOr[list[int]] = None 2465 if raw_enabled_indexes := payload.get("enableFailIndexes"): 2466 enable_fail_indexes = [int(k) for k in raw_enabled_indexes] 2467 2468 return items.PlugItemState( 2469 item_hash=item_hash, 2470 insert_fail_indexes=insert_fail_indexes, 2471 enable_fail_indexes=enable_fail_indexes, 2472 is_enabled=payload["enabled"], 2473 can_insert=payload["canInsert"], 2474 )
67@typing.final 68class FireteamActivity(int, enums.Enum): 69 """An enum for the fireteam activities.""" 70 71 ALL = 0 72 CRUCIBLE = 2 73 TRIALS_OF_OSIRIS = 3 74 NIGHTFALL = 4 75 ANY = 5 76 GAMBIT = 6 77 BLIND_WELL = 7 78 NIGHTMARE_HUNTS = 12 79 ALTARS_OF_SORROWS = 14 80 DUNGEON = 15 81 RAID_LW = 20 82 RAID_GOS = 21 83 RAID_DSC = 22 84 EXO_CHALLENGE = 23 85 S12_WRATHBORN = 24 86 EMPIRE_HUNTS = 25 87 S13_BATTLEGROUNDS = 26 88 EXOTIC_QUEST = 27 89 RAID_VOG = 28 90 S14_EXPUNGE = 30 91 S15_ASTRAL_ALIGNMENT = 31 92 S15_SHATTERED_RELAM = 32 93 SHATTERED_THRONE = 33 94 PROPHECY = 34 95 PIT_OF_HERESY = 35 96 DOE = 36 97 """Dares of Eternity.""" 98 DUNGEON_GOA = 37 99 """Grasp of Avarice.""" 100 VOW_OF_THE_DISCPILE = 38 101 CAMPAIGN = 39 102 WELLSPRING = 40 103 S16_BATTLEGROUNDS = 41 104 S17_NIGHTMARE_CONTAINMENT = 44 105 S17_SEVER = 45
An enum for the fireteam activities.
131@typing.final 132class FireteamDate(int, enums.Enum): 133 """An enum for fireteam date ranges.""" 134 135 ALL = 0 136 NOW = 1 137 TODAY = 2 138 TWO_DAYS = 3 139 THIS_WEEK = 4
An enum for fireteam date ranges.
108@typing.final 109class FireteamLanguage(str, enums.Enum): 110 """An enum for fireteams languages filters.""" 111 112 ALL = "" 113 ENGLISH = "en" 114 FRENCH = "fr" 115 ESPANOL = "es" 116 DEUTSCH = "de" 117 ITALIAN = "it" 118 JAPANESE = "ja" 119 PORTUGUESE = "pt-br" 120 RUSSIAN = "ru" 121 POLISH = "pl" 122 KOREAN = "ko" 123 # ? China 124 ZH_CHT = "zh-cht" 125 ZH_CHS = "zh-chs" 126 127 def __str__(self) -> str: 128 return str(self.value)
An enum for fireteams languages filters.
Inherited Members
- builtins.str
- encode
- replace
- split
- rsplit
- join
- capitalize
- casefold
- title
- center
- count
- expandtabs
- find
- partition
- index
- ljust
- lower
- lstrip
- rfind
- rindex
- rjust
- rstrip
- rpartition
- splitlines
- strip
- swapcase
- translate
- upper
- startswith
- endswith
- removeprefix
- removesuffix
- isascii
- islower
- isupper
- istitle
- isspace
- isdecimal
- isdigit
- isnumeric
- isalpha
- isalnum
- isidentifier
- isprintable
- zfill
- format
- format_map
- maketrans
54@typing.final 55class FireteamPlatform(int, enums.Enum): 56 """An enum for fireteam related to bungie fireteams. 57 This is different from the normal `aiobungie.MembershipType`. 58 """ 59 60 ANY = 0 61 PSN_NETWORK = 1 62 XBOX_LIVE = 2 63 STEAM = 4 64 STADIA = 5
An enum for fireteam related to bungie fireteams.
This is different from the normal aiobungie.MembershipType.
91class Flag(__enum.Flag): 92 """Builtin Python enum flag with extra handlings.""" 93 94 # Needs to type this here for mypy 95 _value_: int 96 97 @property 98 def name(self) -> str: # type: ignore[override] 99 if self._name_ is None: 100 self._name_ = f"UNKNOWN {self._value_}" 101 102 return self._name_ 103 104 @property 105 def value(self) -> int: # type: ignore[override] 106 return self._value_ 107 108 def __str__(self) -> str: 109 return self.name 110 111 def __repr__(self) -> str: 112 return f"<{type(self).__name__}.{self.name}: {self._value_!s}>" 113 114 def __int__(self) -> int: 115 return int(self.value) 116 117 def __or__(self, other: typing.Union[Flag, int]) -> Flag: 118 return self.__class__(self._value_ | int(other)) 119 120 def __xor__(self, other: typing.Union[Flag, int]) -> Flag: 121 return self.__class__(self._value_ ^ int(other)) 122 123 def __and__(self, other: typing.Union[Flag, int]) -> Flag: 124 return self.__class__(other & int(other)) 125 126 def __invert__(self) -> Flag: 127 return self.__class__(~self._value_) 128 129 def __contains__(self, other: typing.Union[Flag, int]) -> bool: 130 return self.value & int(other) == int(other)
Builtin Python enum flag with extra handlings.
136@attrs.define(auto_exc=True) 137class Forbidden(HTTPException): 138 """Exception that's raised for when status code 403 occurs.""" 139 140 http_status: http.HTTPStatus = attrs.field( 141 default=http.HTTPStatus.FORBIDDEN, init=False 142 )
Exception that's raised for when status code 403 occurs.
2def __init__(self, *, error_code, throttle_seconds, url, body, headers, message, error_status, message_data): 3 self.error_code = error_code 4 self.throttle_seconds = throttle_seconds 5 self.url = url 6 self.body = body 7 self.headers = headers 8 self.message = message 9 self.error_status = error_status 10 self.message_data = message_data 11 self.http_status = attr_dict['http_status'].default 12 BaseException.__init__(self, self.error_code,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)
Method generated by attrs for class Forbidden.
Inherited Members
- builtins.BaseException
- with_traceback
- args
259@typing.final 260class GameMode(int, Enum): 261 """An Enum for all available gamemodes in Destiny 2.""" 262 263 NONE = 0 264 STORY = 2 265 STRIKE = 3 266 RAID = 4 267 ALLPVP = 5 268 PATROL = 6 269 ALLPVE = 7 270 RESERVED9 = 9 271 CONTROL = 10 272 RESERVED11 = 11 273 CLASH = 12 274 RESERVED13 = 13 275 CRIMSONDOUBLES = 15 276 NIGHTFALL = 16 277 HEROICNIGHTFALL = 17 278 ALLSTRIKES = 18 279 IRONBANNER = 19 280 RESERVED20 = 20 281 RESERVED21 = 21 282 RESERVED22 = 22 283 RESERVED24 = 24 284 ALLMAYHEM = 25 285 RESERVED26 = 26 286 RESERVED27 = 27 287 RESERVED28 = 28 288 RESERVED29 = 29 289 RESERVED30 = 30 290 SUPREMACY = 31 291 PRIVATEMATCHESALL = 32 292 SURVIVAL = 37 293 COUNTDOWN = 38 294 TRIALSOFTHENINE = 39 295 SOCIAL = 40 296 TRIALSCOUNTDOWN = 41 297 TRIALSSURVIVAL = 42 298 IRONBANNERCONTROL = 43 299 IRONBANNERCLASH = 44 300 IRONBANNERSUPREMACY = 45 301 SCOREDNIGHTFALL = 46 302 SCOREDHEROICNIGHTFALL = 47 303 RUMBLE = 48 304 ALLDOUBLES = 49 305 DOUBLES = 50 306 PRIVATEMATCHESCLASH = 51 307 PRIVATEMATCHESCONTROL = 52 308 PRIVATEMATCHESSUPREMACY = 53 309 PRIVATEMATCHESCOUNTDOWN = 54 310 PRIVATEMATCHESSURVIVAL = 55 311 PRIVATEMATCHESMAYHEM = 56 312 PRIVATEMATCHESRUMBLE = 57 313 HEROICADVENTURE = 58 314 SHOWDOWN = 59 315 LOCKDOWN = 60 316 SCORCHED = 61 317 SCORCHEDTEAM = 62 318 GAMBIT = 63 319 ALLPVECOMPETITIVE = 64 320 BREAKTHROUGH = 65 321 BLACKARMORYRUN = 66 322 SALVAGE = 67 323 IRONBANNERSALVAGE = 68 324 PVPCOMPETITIVE = 69 325 PVPQUICKPLAY = 70 326 CLASHQUICKPLAY = 71 327 CLASHCOMPETITIVE = 72 328 CONTROLQUICKPLAY = 73 329 CONTROLCOMPETITIVE = 74 330 GAMBITPRIME = 75 331 RECKONING = 76 332 MENAGERIE = 77 333 VEXOFFENSIVE = 78 334 NIGHTMAREHUNT = 79 335 ELIMINATION = 80 336 MOMENTUM = 81 337 DUNGEON = 82 338 SUNDIAL = 83 339 TRIALS_OF_OSIRIS = 84 340 DARES = 85 341 OFFENSIVE = 86 342 LOSTSECTOR = 87 343 RIFT = 88 344 ZONECONTROL = 89 345 IRONBANNERRIFT = 90
An Enum for all available gamemodes in Destiny 2.
58@typing.final 59class GatingScope(int, enums.Enum): 60 """An enum represents restrictive type of gating that is being performed by an entity. 61 62 This is useful as a shortcut to avoid a lot of lookups when determining whether the gating on an Entity 63 applies to everyone equally, or to their specific Profile or Character states. 64 """ 65 66 NONE = 0 67 GLOBAL = 1 68 CLAN = 2 69 PROFILE = 3 70 CHARACTER = 4 71 ITEM = 5 72 ASSUMED_WORST_CASE = 6
An enum represents restrictive type of gating that is being performed by an entity.
This is useful as a shortcut to avoid a lot of lookups when determining whether the gating on an Entity applies to everyone equally, or to their specific Profile or Character states.
476@typing.final 477class Gender(int, Enum): 478 """An Enum for Destiny Genders.""" 479 480 MALE = 0 481 FEMALE = 1 482 UNKNOWN = 2
An Enum for Destiny Genders.
645@typing.final 646class GroupType(int, Enum): 647 """An enums for the known bungie group types.""" 648 649 GENERAL = 0 650 CLAN = 1
An enums for the known bungie group types.
78@attrs.define(auto_exc=True) 79class HTTPError(AiobungieError): 80 """Base HTTP request errors exception.""" 81 82 message: str 83 """The error message.""" 84 85 http_status: http.HTTPStatus 86 """The response status."""
Base HTTP request errors exception.
2def __init__(self, message, http_status): 3 self.message = message 4 self.http_status = http_status 5 BaseException.__init__(self, self.message,self.http_status)
Method generated by attrs for class HTTPError.
Inherited Members
- builtins.BaseException
- with_traceback
- args
89@attrs.define(auto_exc=True, kw_only=True) 90class HTTPException(HTTPError): 91 """An in-depth HTTP exception that's raised with more information.""" 92 93 error_code: int 94 """The returned Bungie error status code.""" 95 96 http_status: http.HTTPStatus 97 """The request response http status.""" 98 99 throttle_seconds: int 100 """The Bungie response throttle seconds.""" 101 102 url: typing.Optional[typedefs.StrOrURL] 103 """The URL/endpoint caused this error.""" 104 105 body: typing.Any 106 """The response body.""" 107 108 headers: multidict.CIMultiDictProxy[str] 109 """The response headers.""" 110 111 message: str 112 """A Bungie human readable message describes the cause of the error.""" 113 114 error_status: str 115 """A Bungie short error status describes the cause of the error.""" 116 117 message_data: dict[str, str] 118 """A dict of string key, value that includes each cause of the error 119 to a message describes information about that error. 120 """ 121 122 def __str__(self) -> str: 123 if self.message: 124 message_body = self.message 125 126 if self.error_status: 127 error_status_body = self.error_status 128 129 return ( 130 f"{self.http_status.name.replace('_', '').title()} {self.http_status.value}: " 131 f"Error status: {error_status_body}, Error message: {message_body} from {self.url} " 132 f"{str(self.body)}" 133 )
An in-depth HTTP exception that's raised with more information.
2def __init__(self, *, error_code, http_status, throttle_seconds, url, body, headers, message, error_status, message_data): 3 self.error_code = error_code 4 self.http_status = http_status 5 self.throttle_seconds = throttle_seconds 6 self.url = url 7 self.body = body 8 self.headers = headers 9 self.message = message 10 self.error_status = error_status 11 self.message_data = message_data 12 BaseException.__init__(self, self.error_code,self.http_status,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)
Method generated by attrs for class HTTPException.
A dict of string key, value that includes each cause of the error to a message describes information about that error.
Inherited Members
- builtins.BaseException
- with_traceback
- args
71class Image: 72 """Representation of an image/avatar/picture at Bungie. 73 74 Example 75 ------- 76 ```py 77 from aiobungie import Image 78 img = Image("img/destiny_content/pgcr/raid_eclipse.jpg") 79 print(img) 80 # https://www.bungie.net/img/destiny_content/pgcr/raid_eclipse.jpg 81 82 # Stream the image. 83 async for chunk in img: 84 # Byte chunks of the image. 85 print(chunk) 86 87 # Save the image to a file. 88 await img.save("file_name", "/my/path/to/save/to", "jpeg") 89 ``` 90 91 Parameters 92 ---------- 93 path : `str | None` 94 The path to the image. If `None`, the default missing image path will be used. 95 """ 96 97 __slots__ = ("_path",) 98 99 def __init__(self, path: typing.Optional[str] = None) -> None: 100 self._path = path 101 102 @property 103 def is_missing(self) -> bool: 104 return not self._path 105 106 @property 107 def url(self) -> str: 108 """The URL to the image.""" 109 return self.create_url() 110 111 @staticmethod 112 def missing_path() -> str: 113 """Returns the path to the missing Bungie image.""" 114 return "img/misc/missing_icon_d2.png" 115 116 def create_url(self) -> str: 117 """Creates a full URL to the image path. 118 119 Returns 120 ------- 121 str 122 The URL to the image. 123 """ 124 return f"{url.BASE}/{self._path if self._path else self.missing_path()}" 125 126 async def save( 127 self, 128 file_name: str, 129 path: typing.Union[pathlib.Path, str], 130 /, 131 mime_type: typing.Optional[typing.Union[MimeType, str]] = None, 132 ) -> None: 133 """Saves the image to a file. 134 135 Parameters 136 ---------- 137 file_name : `str` 138 A name for the file to save the image to. 139 path : `pathlib.Path | str` 140 A path tp save the image to. 141 142 Other Parameters 143 ---------------- 144 mime_type : `MimeType | str` 145 Optional MIME type of the image. 146 147 Raises 148 ------ 149 `FileNotFoundError` 150 If the path provided does not exist. 151 `RuntimeError` 152 If the image could not be saved. 153 `PermissionError` 154 If the path provided is not writable or does not have write permissions. 155 """ 156 if isinstance(path, pathlib.Path) and not path.exists(): 157 raise FileNotFoundError(f"File does not exist: {path!r}") 158 159 if self.is_missing: 160 return 161 162 mimetype = mime_type or MimeType.PNG 163 path = pathlib.Path(path) 164 165 loop = helpers.get_or_make_loop() 166 pool = concurrent.futures.ThreadPoolExecutor() 167 168 try: 169 with pool: 170 await loop.run_in_executor( 171 pool, _write, path, file_name, mimetype, await self.read() 172 ) 173 _LOGGER.info("Saved image to %s", file_name) 174 175 except asyncio.CancelledError: 176 pass 177 178 except Exception as err: 179 raise RuntimeError("Encountered an error while saving image.") from err 180 181 async def read(self) -> bytes: 182 """Read this image bytes. 183 184 Returns 185 ------- 186 `bytes` 187 The bytes of this image. 188 """ 189 client_session = aiohttp.ClientSession() 190 191 try: 192 await client_session.__aenter__() 193 response = await client_session.get(self.create_url()) 194 195 if 300 >= response.status >= 200: 196 reader = await response.read() 197 198 except Exception as exc: 199 raise RuntimeError(f"Failed to read image: {exc}") from None 200 finally: 201 await client_session.__aexit__(None, None, None) 202 return reader 203 204 async def iter(self) -> collections.AsyncGenerator[bytes, None]: 205 """Iterates over the image bytes lazily. 206 207 Example 208 ------- 209 import aiobungie 210 211 resource = aiobungie.Image("img/misc/missing_icon_d2.png") 212 async for chunk in resource.iter(): 213 print(chunk) 214 215 Returns 216 ------- 217 `collections.AsyncGenerator[bytes, None]` 218 An async generator of the image bytes. 219 """ 220 221 async for chunk in self: 222 yield chunk 223 224 def __repr__(self) -> str: 225 return f"Image(url={self.create_url()})" 226 227 def __str__(self) -> str: 228 return self.create_url() 229 230 def __aiter__(self) -> Image: 231 return self 232 233 async def __anext__(self) -> bytes: 234 return await self.read() 235 236 def __await__(self) -> collections.Generator[None, None, bytes]: 237 return self.__anext__().__await__()
Representation of an image/avatar/picture at Bungie.
Example
from aiobungie import Image
img = Image("img/destiny_content/pgcr/raid_eclipse.jpg")
print(img)
# https://www.bungie.net/img/destiny_content/pgcr/raid_eclipse.jpg
# Stream the image.
async for chunk in img:
# Byte chunks of the image.
print(chunk)
# Save the image to a file.
await img.save("file_name", "/my/path/to/save/to", "jpeg")
Parameters
- path (
str | None): The path to the image. IfNone, the default missing image path will be used.
111 @staticmethod 112 def missing_path() -> str: 113 """Returns the path to the missing Bungie image.""" 114 return "img/misc/missing_icon_d2.png"
Returns the path to the missing Bungie image.
116 def create_url(self) -> str: 117 """Creates a full URL to the image path. 118 119 Returns 120 ------- 121 str 122 The URL to the image. 123 """ 124 return f"{url.BASE}/{self._path if self._path else self.missing_path()}"
Creates a full URL to the image path.
Returns
- str: The URL to the image.
126 async def save( 127 self, 128 file_name: str, 129 path: typing.Union[pathlib.Path, str], 130 /, 131 mime_type: typing.Optional[typing.Union[MimeType, str]] = None, 132 ) -> None: 133 """Saves the image to a file. 134 135 Parameters 136 ---------- 137 file_name : `str` 138 A name for the file to save the image to. 139 path : `pathlib.Path | str` 140 A path tp save the image to. 141 142 Other Parameters 143 ---------------- 144 mime_type : `MimeType | str` 145 Optional MIME type of the image. 146 147 Raises 148 ------ 149 `FileNotFoundError` 150 If the path provided does not exist. 151 `RuntimeError` 152 If the image could not be saved. 153 `PermissionError` 154 If the path provided is not writable or does not have write permissions. 155 """ 156 if isinstance(path, pathlib.Path) and not path.exists(): 157 raise FileNotFoundError(f"File does not exist: {path!r}") 158 159 if self.is_missing: 160 return 161 162 mimetype = mime_type or MimeType.PNG 163 path = pathlib.Path(path) 164 165 loop = helpers.get_or_make_loop() 166 pool = concurrent.futures.ThreadPoolExecutor() 167 168 try: 169 with pool: 170 await loop.run_in_executor( 171 pool, _write, path, file_name, mimetype, await self.read() 172 ) 173 _LOGGER.info("Saved image to %s", file_name) 174 175 except asyncio.CancelledError: 176 pass 177 178 except Exception as err: 179 raise RuntimeError("Encountered an error while saving image.") from err
Saves the image to a file.
Parameters
- file_name (
str): A name for the file to save the image to. - path (
pathlib.Path | str): A path tp save the image to.
Other Parameters
- mime_type (
MimeType | str): Optional MIME type of the image.
Raises
FileNotFoundError: If the path provided does not exist.RuntimeError: If the image could not be saved.PermissionError: If the path provided is not writable or does not have write permissions.
181 async def read(self) -> bytes: 182 """Read this image bytes. 183 184 Returns 185 ------- 186 `bytes` 187 The bytes of this image. 188 """ 189 client_session = aiohttp.ClientSession() 190 191 try: 192 await client_session.__aenter__() 193 response = await client_session.get(self.create_url()) 194 195 if 300 >= response.status >= 200: 196 reader = await response.read() 197 198 except Exception as exc: 199 raise RuntimeError(f"Failed to read image: {exc}") from None 200 finally: 201 await client_session.__aexit__(None, None, None) 202 return reader
Read this image bytes.
Returns
bytes: The bytes of this image.
204 async def iter(self) -> collections.AsyncGenerator[bytes, None]: 205 """Iterates over the image bytes lazily. 206 207 Example 208 ------- 209 import aiobungie 210 211 resource = aiobungie.Image("img/misc/missing_icon_d2.png") 212 async for chunk in resource.iter(): 213 print(chunk) 214 215 Returns 216 ------- 217 `collections.AsyncGenerator[bytes, None]` 218 An async generator of the image bytes. 219 """ 220 221 async for chunk in self: 222 yield chunk
Iterates over the image bytes lazily.
Example
import aiobungie
resource = aiobungie.Image("img/misc/missing_icon_d2.png") async for chunk in resource.iter(): print(chunk)
Returns
collections.AsyncGenerator[bytes, None]: An async generator of the image bytes.
242@attrs.define(auto_exc=True) 243class InternalServerError(HTTPException): 244 """Raised for 5xx internal server errors."""
Raised for 5xx internal server errors.
2def __init__(self, *, error_code, http_status, throttle_seconds, url, body, headers, message, error_status, message_data): 3 self.error_code = error_code 4 self.http_status = http_status 5 self.throttle_seconds = throttle_seconds 6 self.url = url 7 self.body = body 8 self.headers = headers 9 self.message = message 10 self.error_status = error_status 11 self.message_data = message_data 12 BaseException.__init__(self, self.error_code,self.http_status,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)
Method generated by attrs for class InternalServerError.
Inherited Members
- HTTPException
- error_code
- http_status
- throttle_seconds
- url
- body
- headers
- message
- error_status
- message_data
- builtins.BaseException
- with_traceback
- args
711@typing.final 712class ItemBindStatus(int, Enum): 713 """An enum for Destiny 2 items bind status.""" 714 715 NOT_BOUND = 0 716 BOUND_TO_CHARACTER = 1 717 BOUND_TO_ACCOUNT = 2 718 BOUNT_TO_GUILD = 3
An enum for Destiny 2 items bind status.
721@typing.final 722class ItemLocation(int, Enum): 723 """An enum for Destiny 2 items location.""" 724 725 UNKNOWN = 0 726 INVENTORY = 1 727 VAULT = 2 728 VENDOR = 3 729 POSTMASTER = 4
An enum for Destiny 2 items location.
746@typing.final 747class ItemState(Flag): 748 """An enum for Destiny 2 item states.""" 749 750 NONE = 0 751 LOCKED = 1 << 0 752 TRACKED = 1 << 1 753 MASTERWORKED = 1 << 2 754 CRAFTED = 1 << 3 755 """If this bit is set, the item has been 'crafted' by the player.""" 756 HIGHLITED_OBJECTIVE = 1 << 4 757 """If this bit is set, the item is a 'highlighted' objective."""
An enum for Destiny 2 item states.
If this bit is set, the item is a 'highlighted' objective.
578@typing.final 579class ItemSubType(int, Enum): 580 """An enum for Destiny 2 inventory items subtype.""" 581 582 NONE = 0 583 AUTORIFLE = 6 584 SHOTGUN = 7 585 MACHINEGUN = 8 586 HANDCANNON = 9 587 ROCKETLAUNCHER = 10 588 FUSIONRIFLE = 11 589 SNIPERRIFLE = 12 590 PULSERIFLE = 13 591 SCOUTRIFLE = 14 592 SIDEARM = 17 593 SWORD = 18 594 MASK = 19 595 SHADER = 20 596 ORNAMENT = 21 597 FUSIONRIFLELINE = 22 598 GRENADELAUNCHER = 23 599 SUBMACHINEGUN = 24 600 TRACERIFLE = 25 601 HELMETARMOR = 26 602 GAUNTLETSARMOR = 27 603 CHESTARMOR = 28 604 LEGARMOR = 29 605 CLASSARMOR = 30 606 BOW = 31 607 DUMMYREPEATABLEBOUNTY = 32
An enum for Destiny 2 inventory items subtype.
610@typing.final 611class ItemTier(int, Enum): 612 """An enum for a Destiny 2 item tier.""" 613 614 NONE = 0 615 BASIC = 3340296461 616 COMMON = 2395677314 617 RARE = 2127292149 618 LEGENDERY = 4008398120 619 EXOTIC = 2759499571
An enum for a Destiny 2 item tier.
545@typing.final 546class ItemType(int, Enum): 547 """Enums for Destiny2's item types.""" 548 549 NONE = 0 550 CURRENCY = 1 551 ARMOR = 2 552 WEAPON = 3 553 MESSAGE = 7 554 ENGRAM = 8 555 CONSUMABLE = 9 556 EXCHANGEMATERIAL = 10 557 MISSIONREWARD = 11 558 QUESTSTEP = 12 559 QUESTSTEPCOMPLETE = 13 560 EMBLEM = 14 561 QUEST = 15 562 SUBCLASS = 16 563 CLANBANNER = 17 564 AURA = 18 565 MOD = 19 566 DUMMY = 20 567 SHIP = 21 568 VEHICLE = 22 569 EMOTE = 23 570 GHOST = 24 571 PACKAGE = 25 572 BOUNTY = 26 573 WRAPPER = 27 574 SEASONALARTIFACT = 28 575 FINISHER = 29
Enums for Destiny2's item types.
47class Iterator(typing.Generic[Item], collections.Iterator[Item]): 48 """A Flat, In-Memory iterator for sequenced based data. 49 50 Example 51 ------- 52 ```py 53 iterator = Iterator([1, 2, 3]) 54 55 # Map the results. 56 for item in iterator.map(lambda item: item * 2): 57 print(item) 58 # 2 59 # 4 60 61 # Indexing is also supported. 62 print(iterator[0]) 63 # 1 64 65 # Normal iteration. 66 for item in iterator: 67 print(item) 68 # 1 69 # 2 70 # 3 71 72 # Union two iterators. 73 iterator2 = Iterator([4, 5, 6]) 74 final = iterator | iterator2 75 # <Iterator([1, 2, 3, 4, 5, 6])> 76 ``` 77 78 Parameters 79 ---------- 80 items: `collections.Iterable[Item]` 81 The items to iterate over. 82 """ 83 84 __slots__ = ("_items",) 85 86 def __init__(self, items: collections.Iterable[Item]) -> None: 87 self._items = _builtins.iter(items) 88 89 @typing.overload 90 def collect(self) -> list[Item]: 91 ... 92 93 @typing.overload 94 def collect(self, casting: _B) -> list[_B]: 95 ... 96 97 def copied(self) -> Iterator[Item]: 98 """Creates an iterator which `deeply` copies all of its elements. 99 100 Example 101 ------- 102 ```py 103 it = Iterator([None, None, None]) 104 copied_iter = it.copied() 105 assert it.collect() == copied.collect() 106 ``` 107 """ 108 return self.__class__(_copy.deepcopy(self._items)) 109 110 def collect( 111 self, casting: typing.Optional[_B] = None 112 ) -> typing.Union[list[Item], list[_B]]: 113 """Collects all items in the iterator into a list and cast them into an object if provided. 114 115 Example 116 ------- 117 >>> iterator = Iterator([1, 2, 3]) 118 >>> iterator.collect(casting=str) 119 ["1", "2", "3"] 120 121 Parameters 122 ---------- 123 casting: `T | None` 124 The type to cast the items to. If `None` is provided, the items will be returned as is. 125 126 Raises 127 ------ 128 `StopIteration` 129 If no elements are left in the iterator. 130 """ 131 if casting is not None: 132 return typing.cast(list[_B], list(map(casting, self._items))) 133 134 return list(self._items) 135 136 def next(self) -> Item: 137 """Returns the next item in the iterator. 138 139 Example 140 ------- 141 ```py 142 iterator = Iterator(["1", "2", "3"]) 143 item = iterator.next() 144 assert item == "1" 145 item = iterator.next() 146 assert item == "2" 147 ``` 148 149 Raises 150 ------ 151 `StopIteration` 152 If no elements are left in the iterator. 153 """ 154 try: 155 return self.__next__() 156 except StopIteration: 157 self._ok() 158 159 def map( 160 self, predicate: collections.Callable[[Item], OtherItem] 161 ) -> Iterator[OtherItem]: 162 """Maps each item in the iterator to its predicated value. 163 164 Example 165 ------- 166 ```py 167 iterator = Iterator(["1", "2", "3"]).map(lambda value: int(value)) 168 print(iterator) 169 # <Iterator([1, 2, 3])> 170 ``` 171 172 Parameters 173 ---------- 174 predicate: `collections.Callable[[Item], OtherItem]` 175 The function to map each item in the iterator to its predicated value. 176 177 Returns 178 ------- 179 `Iterator[OtherItem]` 180 The mapped iterator. 181 182 Raises 183 ------ 184 `StopIteration` 185 If no elements are left in the iterator. 186 """ 187 return Iterator(map(predicate, self._items)) 188 189 def take(self, n: int) -> Iterator[Item]: 190 """Take the first number of items until the number of items are yielded or 191 the end of the iterator is reached. 192 193 Example 194 ------- 195 ```py 196 iterator = Iterator([GameMode.RAID, GameMode.STRIKE, GameMode.GAMBIT]) 197 print(iterator.take(2)) 198 # <Iterator([GameMode.RAID, GameMode.STRIKE])> 199 ``` 200 201 Parameters 202 ---------- 203 n: `int` 204 The number of items to take. 205 206 Raises 207 ------ 208 `StopIteration` 209 If no elements are left in the iterator. 210 """ 211 return Iterator(itertools.islice(self._items, n)) 212 213 def take_while( 214 self, predicate: collections.Callable[[Item], bool] 215 ) -> Iterator[Item]: 216 """Yields items from the iterator while predicate returns `True`. 217 218 Example 219 ------- 220 ```py 221 iterator = Iterator([STEAM, XBOX, STADIA]) 222 print(iterator.take_while(lambda platform: platform is not XBOX)) 223 # <Iterator([STEAM])> 224 ``` 225 226 Parameters 227 ---------- 228 predicate: `collections.Callable[[Item], bool]` 229 The function to predicate each item in the iterator. 230 231 Raises 232 ------ 233 `StopIteration` 234 If no elements are left in the iterator. 235 """ 236 return Iterator(itertools.takewhile(predicate, self._items)) 237 238 def drop_while( 239 self, predicate: collections.Callable[[Item], bool] 240 ) -> Iterator[Item]: 241 """Yields items from the iterator while predicate returns `False`. 242 243 Example 244 ------- 245 ```py 246 iterator = Iterator([DestinyMembership(name="Jim"), DestinyMembership(name="Bob")]) 247 print(iterator.drop_while(lambda membership: membership.name is not "Jim")) 248 # <Iterator([DestinyMembership(name="Bob")])> 249 ``` 250 251 Parameters 252 ---------- 253 predicate: `collections.Callable[[Item], bool]` 254 The function to predicate each item in the iterator. 255 256 Raises 257 ------ 258 `StopIteration` 259 If no elements are left in the iterator. 260 """ 261 return Iterator(itertools.dropwhile(predicate, self._items)) 262 263 def filter(self, predicate: collections.Callable[[Item], bool]) -> Iterator[Item]: 264 """Filters the iterator to only yield items that match the predicate. 265 266 Example 267 ------- 268 ```py 269 names = Iterator(["Jim", "Bob", "Mike", "Jess"]) 270 print(names.filter(lambda n: n != "Jim")) 271 # <Iterator(["Bob", "Mike", "Jess"])> 272 ``` 273 """ 274 return Iterator(filter(predicate, self._items)) 275 276 def skip(self, n: int) -> Iterator[Item]: 277 """Skips the first number of items in the iterator. 278 279 Example 280 ------- 281 ```py 282 iterator = Iterator([STEAM, XBOX, STADIA]) 283 print(iterator.skip(1)) 284 # <Iterator([XBOX, STADIA])> 285 ``` 286 """ 287 return Iterator(itertools.islice(self._items, n, None)) 288 289 def zip(self, other: Iterator[OtherItem]) -> Iterator[tuple[Item, OtherItem]]: 290 """Zips the iterator with another iterable. 291 292 Example 293 ------- 294 ```py 295 iterator = Iterator([1, 3, 5]) 296 other = Iterator([2, 4, 6]) 297 for item, other_item in iterator.zip(other): 298 print(item, other_item) 299 # <Iterator([(1, 2), (3, 4), (5, 6)])> 300 ``` 301 302 Parameters 303 ---------- 304 other: `Iterator[OtherItem]` 305 The iterable to zip with. 306 307 Raises 308 ------ 309 `StopIteration` 310 If no elements are left in the iterator. 311 """ 312 return Iterator(zip(self._items, other)) 313 314 def all(self, predicate: collections.Callable[[Item], bool]) -> bool: 315 """`True` if all items in the iterator match the predicate. 316 317 Example 318 ------- 319 ```py 320 iterator = Iterator([1, 2, 3]) 321 while iterator.all(lambda item: isinstance(item, int)): 322 print("Still all integers") 323 continue 324 # Still all integers 325 ``` 326 327 Parameters 328 ---------- 329 predicate: `collections.Callable[[Item], bool]` 330 The function to test each item in the iterator. 331 332 Raises 333 ------ 334 `StopIteration` 335 If no elements are left in the iterator. 336 """ 337 return all(predicate(item) for item in self) 338 339 def any(self, predicate: collections.Callable[[Item], bool]) -> bool: 340 """`True` if any items in the iterator match the predicate. 341 342 Example 343 ------- 344 ```py 345 iterator = Iterator([1, 2, 3]) 346 if iterator.any(lambda item: isinstance(item, int)): 347 print("At least one item is an int.") 348 # At least one item is an int. 349 ``` 350 351 Parameters 352 ---------- 353 predicate: `collections.Callable[[Item], bool]` 354 The function to test each item in the iterator. 355 356 Raises 357 ------ 358 `StopIteration` 359 If no elements are left in the iterator. 360 """ 361 return any(predicate(item) for item in self) 362 363 def sort( 364 self, 365 *, 366 key: collections.Callable[[Item], typeshed.SupportsRichComparison], 367 reverse: bool = False, 368 ) -> Iterator[Item]: 369 """Sorts the iterator. 370 371 Example 372 ------- 373 ```py 374 iterator = Iterator([3, 1, 6, 7]) 375 print(iterator.sort(key=lambda item: item)) 376 # <Iterator([1, 3, 6, 7])> 377 ``` 378 379 Parameters 380 ---------- 381 key: `collections.Callable[[Item], Any]` 382 The function to sort by. 383 reverse: `bool` 384 Whether to reverse the sort. 385 386 Raises 387 ------ 388 `StopIteration` 389 If no elements are left in the iterator. 390 """ 391 return Iterator(sorted(self._items, key=key, reverse=reverse)) 392 393 def first(self) -> Item: 394 """Returns the first item in the iterator. 395 396 Example 397 ------- 398 ```py 399 iterator = Iterator([3, 1, 6, 7]) 400 print(iterator.first()) 401 3 402 ``` 403 404 Raises 405 ------ 406 `StopIteration` 407 If no elements are left in the iterator. 408 """ 409 return self.take(1).next() 410 411 def reversed(self) -> Iterator[Item]: 412 """Returns a new iterator that yields the items in the iterator in reverse order. 413 414 Example 415 ------- 416 ```py 417 iterator = Iterator([3, 1, 6, 7]) 418 print(iterator.reversed()) 419 # <Iterator([7, 6, 1, 3])> 420 ``` 421 422 Raises 423 ------ 424 `StopIteration` 425 If no elements are left in the iterator. 426 """ 427 return Iterator(reversed(self.collect())) 428 429 def count(self) -> int: 430 """Returns the number of items in the iterator. 431 432 Example 433 ------- 434 ```py 435 iterator = Iterator([3, 1, 6, 7]) 436 print(iterator.count()) 437 4 438 ``` 439 """ 440 count = 0 441 for _ in self: 442 count += 1 443 444 return count 445 446 def union(self, other: Iterator[Item]) -> Iterator[Item]: 447 """Returns a new iterator that yields all items from both iterators. 448 449 Example 450 ------- 451 ```py 452 iterator = Iterator([1, 2, 3]) 453 other = Iterator([4, 5, 6]) 454 print(iterator.union(other)) 455 # <Iterator([1, 2, 3, 4, 5, 6])> 456 ``` 457 458 Parameters 459 ---------- 460 other: `Iterator[Item]` 461 The iterable to union with. 462 463 Raises 464 ------ 465 `StopIteration` 466 If no elements are left in the iterator. 467 """ 468 return Iterator(itertools.chain(self._items, other)) 469 470 def for_each(self, func: collections.Callable[[Item], typing.Any]) -> None: 471 """Calls the function on each item in the iterator. 472 473 Example 474 ------- 475 ```py 476 iterator = Iterator([1, 2, 3]) 477 iterator.for_each(lambda item: print(item)) 478 # 1 479 # 2 480 # 3 481 ``` 482 483 Parameters 484 ---------- 485 func: `typeshed.Callable[[Item], None]` 486 The function to call on each item in the iterator. 487 """ 488 for item in self: 489 func(item) 490 491 async def async_for_each( 492 self, 493 func: collections.Callable[[Item], collections.Coroutine[None, None, None]], 494 ) -> None: 495 """Calls the async function on each item in the iterator concurrently. 496 497 Example 498 ------- 499 ```py 500 async def signup(username: str) -> None: 501 async with aiohttp.request('POST', '...') as r: 502 # Actual logic. 503 ... 504 505 async def main(): 506 users = aiobungie.into_iter(["user_danny", "user_jojo"]) 507 await users.async_for_each(lambda username: signup(username)) 508 ``` 509 510 Parameters 511 ---------- 512 func: `collections.Callable[[Item], collections.Coroutine[None, None, None]]` 513 The async function to call on each item in the iterator. 514 """ 515 await _helpers.awaits(*(func(item) for item in self)) 516 517 def enumerate(self, *, start: int = 0) -> Iterator[tuple[int, Item]]: 518 """Returns a new iterator that yields tuples of the index and item. 519 520 Example 521 ------- 522 ```py 523 iterator = Iterator([1, 2, 3]) 524 for index, item in iterator.enumerate(): 525 print(index, item) 526 # 0 1 527 # 1 2 528 # 2 3 529 ``` 530 531 Raises 532 ------ 533 `StopIteration` 534 If no elements are left in the iterator. 535 """ 536 return Iterator(enumerate(self._items, start=start)) 537 538 def _ok(self) -> typing.NoReturn: 539 raise StopIteration("No more items in the iterator.") from None 540 541 def __getitem__(self, index: int) -> Item: 542 try: 543 return self.skip(index).first() 544 except IndexError: 545 self._ok() 546 547 def __or__(self, other: Iterator[Item]) -> Iterator[Item]: 548 return self.union(other) 549 550 # This is a never. 551 def __setitem__(self) -> typing.NoReturn: 552 raise TypeError( 553 f"{type(self).__name__} doesn't support item assignment." 554 ) from None 555 556 def __repr__(self) -> str: 557 return f'<{self.__class__.__name__}({", ".join([str(item) for item in self])})>' 558 559 def __len__(self) -> int: 560 return self.count() 561 562 def __iter__(self) -> Iterator[Item]: 563 return self 564 565 def __next__(self) -> Item: 566 try: 567 item = next(self._items) 568 except StopIteration: 569 self._ok() 570 571 return item
A Flat, In-Memory iterator for sequenced based data.
Example
iterator = Iterator([1, 2, 3])
# Map the results.
for item in iterator.map(lambda item: item * 2):
print(item)
# 2
# 4
# Indexing is also supported.
print(iterator[0])
# 1
# Normal iteration.
for item in iterator:
print(item)
# 1
# 2
# 3
# Union two iterators.
iterator2 = Iterator([4, 5, 6])
final = iterator | iterator2
# <Iterator([1, 2, 3, 4, 5, 6])>
Parameters
- items (
collections.Iterable[Item]): The items to iterate over.
110 def collect( 111 self, casting: typing.Optional[_B] = None 112 ) -> typing.Union[list[Item], list[_B]]: 113 """Collects all items in the iterator into a list and cast them into an object if provided. 114 115 Example 116 ------- 117 >>> iterator = Iterator([1, 2, 3]) 118 >>> iterator.collect(casting=str) 119 ["1", "2", "3"] 120 121 Parameters 122 ---------- 123 casting: `T | None` 124 The type to cast the items to. If `None` is provided, the items will be returned as is. 125 126 Raises 127 ------ 128 `StopIteration` 129 If no elements are left in the iterator. 130 """ 131 if casting is not None: 132 return typing.cast(list[_B], list(map(casting, self._items))) 133 134 return list(self._items)
Collects all items in the iterator into a list and cast them into an object if provided.
Example
>>> iterator = Iterator([1, 2, 3])
>>> iterator.collect(casting=str)
["1", "2", "3"]
Parameters
- casting (
T | None): The type to cast the items to. IfNoneis provided, the items will be returned as is.
Raises
StopIteration: If no elements are left in the iterator.
97 def copied(self) -> Iterator[Item]: 98 """Creates an iterator which `deeply` copies all of its elements. 99 100 Example 101 ------- 102 ```py 103 it = Iterator([None, None, None]) 104 copied_iter = it.copied() 105 assert it.collect() == copied.collect() 106 ``` 107 """ 108 return self.__class__(_copy.deepcopy(self._items))
Creates an iterator which deeply copies all of its elements.
Example
it = Iterator([None, None, None])
copied_iter = it.copied()
assert it.collect() == copied.collect()
136 def next(self) -> Item: 137 """Returns the next item in the iterator. 138 139 Example 140 ------- 141 ```py 142 iterator = Iterator(["1", "2", "3"]) 143 item = iterator.next() 144 assert item == "1" 145 item = iterator.next() 146 assert item == "2" 147 ``` 148 149 Raises 150 ------ 151 `StopIteration` 152 If no elements are left in the iterator. 153 """ 154 try: 155 return self.__next__() 156 except StopIteration: 157 self._ok()
Returns the next item in the iterator.
Example
iterator = Iterator(["1", "2", "3"])
item = iterator.next()
assert item == "1"
item = iterator.next()
assert item == "2"
Raises
StopIteration: If no elements are left in the iterator.
159 def map( 160 self, predicate: collections.Callable[[Item], OtherItem] 161 ) -> Iterator[OtherItem]: 162 """Maps each item in the iterator to its predicated value. 163 164 Example 165 ------- 166 ```py 167 iterator = Iterator(["1", "2", "3"]).map(lambda value: int(value)) 168 print(iterator) 169 # <Iterator([1, 2, 3])> 170 ``` 171 172 Parameters 173 ---------- 174 predicate: `collections.Callable[[Item], OtherItem]` 175 The function to map each item in the iterator to its predicated value. 176 177 Returns 178 ------- 179 `Iterator[OtherItem]` 180 The mapped iterator. 181 182 Raises 183 ------ 184 `StopIteration` 185 If no elements are left in the iterator. 186 """ 187 return Iterator(map(predicate, self._items))
Maps each item in the iterator to its predicated value.
Example
iterator = Iterator(["1", "2", "3"]).map(lambda value: int(value))
print(iterator)
# <Iterator([1, 2, 3])>
Parameters
- predicate (
collections.Callable[[Item], OtherItem]): The function to map each item in the iterator to its predicated value.
Returns
Iterator[OtherItem]: The mapped iterator.
Raises
StopIteration: If no elements are left in the iterator.
189 def take(self, n: int) -> Iterator[Item]: 190 """Take the first number of items until the number of items are yielded or 191 the end of the iterator is reached. 192 193 Example 194 ------- 195 ```py 196 iterator = Iterator([GameMode.RAID, GameMode.STRIKE, GameMode.GAMBIT]) 197 print(iterator.take(2)) 198 # <Iterator([GameMode.RAID, GameMode.STRIKE])> 199 ``` 200 201 Parameters 202 ---------- 203 n: `int` 204 The number of items to take. 205 206 Raises 207 ------ 208 `StopIteration` 209 If no elements are left in the iterator. 210 """ 211 return Iterator(itertools.islice(self._items, n))
Take the first number of items until the number of items are yielded or the end of the iterator is reached.
Example
iterator = Iterator([GameMode.RAID, GameMode.STRIKE, GameMode.GAMBIT])
print(iterator.take(2))
# <Iterator([GameMode.RAID, GameMode.STRIKE])>
Parameters
- n (
int): The number of items to take.
Raises
StopIteration: If no elements are left in the iterator.
213 def take_while( 214 self, predicate: collections.Callable[[Item], bool] 215 ) -> Iterator[Item]: 216 """Yields items from the iterator while predicate returns `True`. 217 218 Example 219 ------- 220 ```py 221 iterator = Iterator([STEAM, XBOX, STADIA]) 222 print(iterator.take_while(lambda platform: platform is not XBOX)) 223 # <Iterator([STEAM])> 224 ``` 225 226 Parameters 227 ---------- 228 predicate: `collections.Callable[[Item], bool]` 229 The function to predicate each item in the iterator. 230 231 Raises 232 ------ 233 `StopIteration` 234 If no elements are left in the iterator. 235 """ 236 return Iterator(itertools.takewhile(predicate, self._items))
Yields items from the iterator while predicate returns True.
Example
iterator = Iterator([STEAM, XBOX, STADIA])
print(iterator.take_while(lambda platform: platform is not XBOX))
# <Iterator([STEAM])>
Parameters
- predicate (
collections.Callable[[Item], bool]): The function to predicate each item in the iterator.
Raises
StopIteration: If no elements are left in the iterator.
238 def drop_while( 239 self, predicate: collections.Callable[[Item], bool] 240 ) -> Iterator[Item]: 241 """Yields items from the iterator while predicate returns `False`. 242 243 Example 244 ------- 245 ```py 246 iterator = Iterator([DestinyMembership(name="Jim"), DestinyMembership(name="Bob")]) 247 print(iterator.drop_while(lambda membership: membership.name is not "Jim")) 248 # <Iterator([DestinyMembership(name="Bob")])> 249 ``` 250 251 Parameters 252 ---------- 253 predicate: `collections.Callable[[Item], bool]` 254 The function to predicate each item in the iterator. 255 256 Raises 257 ------ 258 `StopIteration` 259 If no elements are left in the iterator. 260 """ 261 return Iterator(itertools.dropwhile(predicate, self._items))
Yields items from the iterator while predicate returns False.
Example
iterator = Iterator([DestinyMembership(name="Jim"), DestinyMembership(name="Bob")])
print(iterator.drop_while(lambda membership: membership.name is not "Jim"))
# <Iterator([DestinyMembership(name="Bob")])>
Parameters
- predicate (
collections.Callable[[Item], bool]): The function to predicate each item in the iterator.
Raises
StopIteration: If no elements are left in the iterator.
263 def filter(self, predicate: collections.Callable[[Item], bool]) -> Iterator[Item]: 264 """Filters the iterator to only yield items that match the predicate. 265 266 Example 267 ------- 268 ```py 269 names = Iterator(["Jim", "Bob", "Mike", "Jess"]) 270 print(names.filter(lambda n: n != "Jim")) 271 # <Iterator(["Bob", "Mike", "Jess"])> 272 ``` 273 """ 274 return Iterator(filter(predicate, self._items))
Filters the iterator to only yield items that match the predicate.
Example
names = Iterator(["Jim", "Bob", "Mike", "Jess"])
print(names.filter(lambda n: n != "Jim"))
# <Iterator(["Bob", "Mike", "Jess"])>
276 def skip(self, n: int) -> Iterator[Item]: 277 """Skips the first number of items in the iterator. 278 279 Example 280 ------- 281 ```py 282 iterator = Iterator([STEAM, XBOX, STADIA]) 283 print(iterator.skip(1)) 284 # <Iterator([XBOX, STADIA])> 285 ``` 286 """ 287 return Iterator(itertools.islice(self._items, n, None))
Skips the first number of items in the iterator.
Example
iterator = Iterator([STEAM, XBOX, STADIA])
print(iterator.skip(1))
# <Iterator([XBOX, STADIA])>
289 def zip(self, other: Iterator[OtherItem]) -> Iterator[tuple[Item, OtherItem]]: 290 """Zips the iterator with another iterable. 291 292 Example 293 ------- 294 ```py 295 iterator = Iterator([1, 3, 5]) 296 other = Iterator([2, 4, 6]) 297 for item, other_item in iterator.zip(other): 298 print(item, other_item) 299 # <Iterator([(1, 2), (3, 4), (5, 6)])> 300 ``` 301 302 Parameters 303 ---------- 304 other: `Iterator[OtherItem]` 305 The iterable to zip with. 306 307 Raises 308 ------ 309 `StopIteration` 310 If no elements are left in the iterator. 311 """ 312 return Iterator(zip(self._items, other))
Zips the iterator with another iterable.
Example
iterator = Iterator([1, 3, 5])
other = Iterator([2, 4, 6])
for item, other_item in iterator.zip(other):
print(item, other_item)
# <Iterator([(1, 2), (3, 4), (5, 6)])>
Parameters
- other (
Iterator[OtherItem]): The iterable to zip with.
Raises
StopIteration: If no elements are left in the iterator.
314 def all(self, predicate: collections.Callable[[Item], bool]) -> bool: 315 """`True` if all items in the iterator match the predicate. 316 317 Example 318 ------- 319 ```py 320 iterator = Iterator([1, 2, 3]) 321 while iterator.all(lambda item: isinstance(item, int)): 322 print("Still all integers") 323 continue 324 # Still all integers 325 ``` 326 327 Parameters 328 ---------- 329 predicate: `collections.Callable[[Item], bool]` 330 The function to test each item in the iterator. 331 332 Raises 333 ------ 334 `StopIteration` 335 If no elements are left in the iterator. 336 """ 337 return all(predicate(item) for item in self)
True if all items in the iterator match the predicate.
Example
iterator = Iterator([1, 2, 3])
while iterator.all(lambda item: isinstance(item, int)):
print("Still all integers")
continue
# Still all integers
Parameters
- predicate (
collections.Callable[[Item], bool]): The function to test each item in the iterator.
Raises
StopIteration: If no elements are left in the iterator.
339 def any(self, predicate: collections.Callable[[Item], bool]) -> bool: 340 """`True` if any items in the iterator match the predicate. 341 342 Example 343 ------- 344 ```py 345 iterator = Iterator([1, 2, 3]) 346 if iterator.any(lambda item: isinstance(item, int)): 347 print("At least one item is an int.") 348 # At least one item is an int. 349 ``` 350 351 Parameters 352 ---------- 353 predicate: `collections.Callable[[Item], bool]` 354 The function to test each item in the iterator. 355 356 Raises 357 ------ 358 `StopIteration` 359 If no elements are left in the iterator. 360 """ 361 return any(predicate(item) for item in self)
True if any items in the iterator match the predicate.
Example
iterator = Iterator([1, 2, 3])
if iterator.any(lambda item: isinstance(item, int)):
print("At least one item is an int.")
# At least one item is an int.
Parameters
- predicate (
collections.Callable[[Item], bool]): The function to test each item in the iterator.
Raises
StopIteration: If no elements are left in the iterator.
363 def sort( 364 self, 365 *, 366 key: collections.Callable[[Item], typeshed.SupportsRichComparison], 367 reverse: bool = False, 368 ) -> Iterator[Item]: 369 """Sorts the iterator. 370 371 Example 372 ------- 373 ```py 374 iterator = Iterator([3, 1, 6, 7]) 375 print(iterator.sort(key=lambda item: item)) 376 # <Iterator([1, 3, 6, 7])> 377 ``` 378 379 Parameters 380 ---------- 381 key: `collections.Callable[[Item], Any]` 382 The function to sort by. 383 reverse: `bool` 384 Whether to reverse the sort. 385 386 Raises 387 ------ 388 `StopIteration` 389 If no elements are left in the iterator. 390 """ 391 return Iterator(sorted(self._items, key=key, reverse=reverse))
Sorts the iterator.
Example
iterator = Iterator([3, 1, 6, 7])
print(iterator.sort(key=lambda item: item))
# <Iterator([1, 3, 6, 7])>
Parameters
- key (
collections.Callable[[Item], Any]): The function to sort by. - reverse (
bool): Whether to reverse the sort.
Raises
StopIteration: If no elements are left in the iterator.
393 def first(self) -> Item: 394 """Returns the first item in the iterator. 395 396 Example 397 ------- 398 ```py 399 iterator = Iterator([3, 1, 6, 7]) 400 print(iterator.first()) 401 3 402 ``` 403 404 Raises 405 ------ 406 `StopIteration` 407 If no elements are left in the iterator. 408 """ 409 return self.take(1).next()
Returns the first item in the iterator.
Example
iterator = Iterator([3, 1, 6, 7])
print(iterator.first())
3
Raises
StopIteration: If no elements are left in the iterator.
411 def reversed(self) -> Iterator[Item]: 412 """Returns a new iterator that yields the items in the iterator in reverse order. 413 414 Example 415 ------- 416 ```py 417 iterator = Iterator([3, 1, 6, 7]) 418 print(iterator.reversed()) 419 # <Iterator([7, 6, 1, 3])> 420 ``` 421 422 Raises 423 ------ 424 `StopIteration` 425 If no elements are left in the iterator. 426 """ 427 return Iterator(reversed(self.collect()))
Returns a new iterator that yields the items in the iterator in reverse order.
Example
iterator = Iterator([3, 1, 6, 7])
print(iterator.reversed())
# <Iterator([7, 6, 1, 3])>
Raises
StopIteration: If no elements are left in the iterator.
429 def count(self) -> int: 430 """Returns the number of items in the iterator. 431 432 Example 433 ------- 434 ```py 435 iterator = Iterator([3, 1, 6, 7]) 436 print(iterator.count()) 437 4 438 ``` 439 """ 440 count = 0 441 for _ in self: 442 count += 1 443 444 return count
Returns the number of items in the iterator.
Example
iterator = Iterator([3, 1, 6, 7])
print(iterator.count())
4
446 def union(self, other: Iterator[Item]) -> Iterator[Item]: 447 """Returns a new iterator that yields all items from both iterators. 448 449 Example 450 ------- 451 ```py 452 iterator = Iterator([1, 2, 3]) 453 other = Iterator([4, 5, 6]) 454 print(iterator.union(other)) 455 # <Iterator([1, 2, 3, 4, 5, 6])> 456 ``` 457 458 Parameters 459 ---------- 460 other: `Iterator[Item]` 461 The iterable to union with. 462 463 Raises 464 ------ 465 `StopIteration` 466 If no elements are left in the iterator. 467 """ 468 return Iterator(itertools.chain(self._items, other))
Returns a new iterator that yields all items from both iterators.
Example
iterator = Iterator([1, 2, 3])
other = Iterator([4, 5, 6])
print(iterator.union(other))
# <Iterator([1, 2, 3, 4, 5, 6])>
Parameters
- other (
Iterator[Item]): The iterable to union with.
Raises
StopIteration: If no elements are left in the iterator.
470 def for_each(self, func: collections.Callable[[Item], typing.Any]) -> None: 471 """Calls the function on each item in the iterator. 472 473 Example 474 ------- 475 ```py 476 iterator = Iterator([1, 2, 3]) 477 iterator.for_each(lambda item: print(item)) 478 # 1 479 # 2 480 # 3 481 ``` 482 483 Parameters 484 ---------- 485 func: `typeshed.Callable[[Item], None]` 486 The function to call on each item in the iterator. 487 """ 488 for item in self: 489 func(item)
Calls the function on each item in the iterator.
Example
iterator = Iterator([1, 2, 3])
iterator.for_each(lambda item: print(item))
# 1
# 2
# 3
Parameters
- func (
typeshed.Callable[[Item], None]): The function to call on each item in the iterator.
491 async def async_for_each( 492 self, 493 func: collections.Callable[[Item], collections.Coroutine[None, None, None]], 494 ) -> None: 495 """Calls the async function on each item in the iterator concurrently. 496 497 Example 498 ------- 499 ```py 500 async def signup(username: str) -> None: 501 async with aiohttp.request('POST', '...') as r: 502 # Actual logic. 503 ... 504 505 async def main(): 506 users = aiobungie.into_iter(["user_danny", "user_jojo"]) 507 await users.async_for_each(lambda username: signup(username)) 508 ``` 509 510 Parameters 511 ---------- 512 func: `collections.Callable[[Item], collections.Coroutine[None, None, None]]` 513 The async function to call on each item in the iterator. 514 """ 515 await _helpers.awaits(*(func(item) for item in self))
Calls the async function on each item in the iterator concurrently.
Example
async def signup(username: str) -> None:
async with aiohttp.request('POST', '...') as r:
# Actual logic.
...
async def main():
users = aiobungie.into_iter(["user_danny", "user_jojo"])
await users.async_for_each(lambda username: signup(username))
Parameters
- func (
collections.Callable[[Item], collections.Coroutine[None, None, None]]): The async function to call on each item in the iterator.
517 def enumerate(self, *, start: int = 0) -> Iterator[tuple[int, Item]]: 518 """Returns a new iterator that yields tuples of the index and item. 519 520 Example 521 ------- 522 ```py 523 iterator = Iterator([1, 2, 3]) 524 for index, item in iterator.enumerate(): 525 print(index, item) 526 # 0 1 527 # 1 2 528 # 2 3 529 ``` 530 531 Raises 532 ------ 533 `StopIteration` 534 If no elements are left in the iterator. 535 """ 536 return Iterator(enumerate(self._items, start=start))
Returns a new iterator that yields tuples of the index and item.
Example
iterator = Iterator([1, 2, 3])
for index, item in iterator.enumerate():
print(index, item)
# 0 1
# 1 2
# 2 3
Raises
StopIteration: If no elements are left in the iterator.
702@typing.final 703class MembershipOption(int, Enum): 704 """A enum for GroupV2 membership options.""" 705 706 REVIEWD = 0 707 OPEN = 1 708 CLOSED = 2
A enum for GroupV2 membership options.
450@typing.final 451class MembershipType(int, Enum): 452 """An Enum for Bungie membership types.""" 453 454 NONE = 0 455 XBOX = 1 456 PSN = 2 457 STEAM = 3 458 BLIZZARD = 4 459 STADIA = 5 460 EPIC_GAMES_STORE = 6 461 DEMON = 10 462 BUNGIE = 254 463 ALL = -1
An Enum for Bungie membership types.
181@attrs.define(auto_exc=True) 182class MembershipTypeError(BadRequest): 183 """A bad request error raised when passing wrong membership to the request. 184 185 Those fields are useful since it returns the correct membership and id which can be used 186 to make the request again with those fields. 187 188 Example 189 ------- 190 ```py 191 try: 192 profile = await client.fetch_profile( 193 member_id=1, 194 type=aiobungie.MembershipType.STADIA, 195 components=[] 196 ) 197 198 # Membership type is wrong! 199 except aiobungie.MembershipTypeError as err: 200 correct_membersip = err.into_membership() 201 profile_id = err.membership_id 202 203 # Recall the method. 204 profile = await client.fetch_profile( 205 member_id=profile_id, 206 type=correct_membership, 207 components=[] 208 ) 209 ``` 210 """ 211 212 membership_type: str 213 """The errored membership type passed to the request.""" 214 215 membership_id: int 216 """The errored user's membership id.""" 217 218 required_membership: str 219 """The required correct membership for errored user.""" 220 221 def into_membership( 222 self, value: typing.Optional[str] = None 223 ) -> enums.MembershipType: 224 """Turn the required membership from `str` into `aiobungie.Membership` type. 225 226 If value parameter is not provided it will fall back to the required membership. 227 """ 228 if value is None: 229 return _DETERMINE_MSHIP(self.required_membership) 230 return _DETERMINE_MSHIP(value) 231 232 def __str__(self) -> str: 233 return ( 234 f"Expected membership: {self.into_membership().name.replace('_', '').title()}, " 235 f"But got {self.into_membership(self.membership_type)} for id {self.membership_id}" 236 ) 237 238 def __int__(self) -> int: 239 return int(self.membership_id)
A bad request error raised when passing wrong membership to the request.
Those fields are useful since it returns the correct membership and id which can be used to make the request again with those fields.
Example
try:
profile = await client.fetch_profile(
member_id=1,
type=aiobungie.MembershipType.STADIA,
components=[]
)
# Membership type is wrong!
except aiobungie.MembershipTypeError as err:
correct_membersip = err.into_membership()
profile_id = err.membership_id
# Recall the method.
profile = await client.fetch_profile(
member_id=profile_id,
type=correct_membership,
components=[]
)
2def __init__(self, message, url, body, headers, membership_type, membership_id, required_membership): 3 self.message = message 4 self.url = url 5 self.body = body 6 self.headers = headers 7 self.http_status = attr_dict['http_status'].default 8 self.membership_type = membership_type 9 self.membership_id = membership_id 10 self.required_membership = required_membership 11 BaseException.__init__(self, self.message,self.url,self.body,self.headers,self.membership_type,self.membership_id,self.required_membership)
Method generated by attrs for class MembershipTypeError.
221 def into_membership( 222 self, value: typing.Optional[str] = None 223 ) -> enums.MembershipType: 224 """Turn the required membership from `str` into `aiobungie.Membership` type. 225 226 If value parameter is not provided it will fall back to the required membership. 227 """ 228 if value is None: 229 return _DETERMINE_MSHIP(self.required_membership) 230 return _DETERMINE_MSHIP(value)
Turn the required membership from str into aiobungie.Membership type.
If value parameter is not provided it will fall back to the required membership.
Inherited Members
- builtins.BaseException
- with_traceback
- args
495@typing.final 496class MilestoneType(int, Enum): 497 """An Enum for Destiny 2 milestone types.""" 498 499 UNKNOWN = 0 500 TUTORIAL = 1 501 ONETIME = 2 502 WEEKLY = 3 503 DAILY = 4 504 SPECIAL = 5
An Enum for Destiny 2 milestone types.
145@attrs.define(auto_exc=True) 146class NotFound(HTTPException): 147 """Raised when an unknown resource was not found.""" 148 149 http_status: http.HTTPStatus = attrs.field( 150 default=http.HTTPStatus.NOT_FOUND, init=False 151 )
Raised when an unknown resource was not found.
2def __init__(self, *, error_code, throttle_seconds, url, body, headers, message, error_status, message_data): 3 self.error_code = error_code 4 self.throttle_seconds = throttle_seconds 5 self.url = url 6 self.body = body 7 self.headers = headers 8 self.message = message 9 self.error_status = error_status 10 self.message_data = message_data 11 self.http_status = attr_dict['http_status'].default 12 BaseException.__init__(self, self.error_code,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)
Method generated by attrs for class NotFound.
Inherited Members
- builtins.BaseException
- with_traceback
- args
94@typing.final 95class ObjectiveUIStyle(int, enums.Enum): 96 NONE = 0 97 HIGHLIGHTED = 1 98 CRAFTING_WEAPON_LEVEL = 2 99 CRAFTING_WEAPON_LEVEL_PROGRESS = 3 100 CRAFTING_WEAPON_TIMESTAMP = 4 101 CRAFTING_MEMENTOS = 5 102 CRAFTING_MEMENTO_TITLE = 6
An enumeration.
220@typing.final 221class Place(int, Enum): 222 """An Enum for Destiny 2 Places and NOT Planets""" 223 224 ORBIT = 2961497387 225 SOCIAL = 4151112093 226 LIGHT_HOUSE = 4276116472 227 EXPLORE = 3497767639
An Enum for Destiny 2 Places and NOT Planets
185@typing.final 186class Planet(int, Enum): 187 """An Enum for all available planets in Destiny 2.""" 188 189 UNKNOWN = 0 190 """Unknown space""" 191 192 EARTH = 3747705955 193 """Earth""" 194 195 DREAMING_CITY = 2877881518 196 """The Dreaming city.""" 197 198 NESSUS = 3526908984 199 """Nessus""" 200 201 MOON = 3325508439 202 """The Moon""" 203 204 COSMODROME = 3990611421 205 """The Cosmodrome""" 206 207 TANGLED_SHORE = 3821439926 208 """The Tangled Shore""" 209 210 VENUS = 3871070152 211 """Venus""" 212 213 EAZ = 541863059 # Exclusive event. 214 """European Aerial Zone""" 215 216 EUROPA = 1729879943 217 """Europa"""
An Enum for all available planets in Destiny 2.
672@typing.final 673class Presence(int, Enum): 674 """An enum for a bungie friend status.""" 675 676 OFFLINE_OR_UNKNOWN = 0 677 ONLINE = 1
An enum for a bungie friend status.
760@typing.final 761class PrivacySetting(int, Enum): 762 """An enum for players's privacy settings.""" 763 764 OPEN = 0 765 CLAN_AND_FRIENDS = 1 766 FRIENDS_ONLY = 2 767 INVITE_ONLY = 3 768 CLOSED = 4
An enum for players's privacy settings.
309class RESTClient(interfaces.RESTInterface): 310 """A RESTful client implementation for Bungie's API. 311 312 This client is designed to only make HTTP requests and return JSON objects 313 to provide RESTful functionality. 314 315 This client is the core for `aiobungie.Client` which deserialize those returned JSON objects 316 using the factory into Pythonic data classes objects which provide Python functionality. 317 318 Example 319 ------- 320 ```py 321 import aiobungie 322 323 client = aiobungie.RESTClient("TOKEN") 324 async with client: 325 response = await client.fetch_clan_members(4389205) 326 for member in response['results']: 327 for key, value in member['destinyUserInfo'].items(): 328 print(key, value) 329 ``` 330 331 Parameters 332 ---------- 333 token : `str` 334 A valid application token from Bungie's developer portal. 335 336 Other Parameters 337 ---------------- 338 max_retries : `int` 339 The max retries number to retry if the request hit a `5xx` status code. 340 client_secret : `typing.Optional[str]` 341 An optional application client secret, 342 This is only needed if you're fetching OAuth2 tokens with this client. 343 client_id : `typing.Optional[int]` 344 An optional application client id, 345 This is only needed if you're fetching OAuth2 tokens with this client. 346 enable_debugging : `bool | str` 347 Whether to enable logging responses or not. 348 349 Logging Levels 350 -------------- 351 * `False`: This will disable logging. 352 * `True`: This will set the level to `DEBUG` and enable logging minimal information. 353 * `"TRACE" | aiobungie.TRACE`: This will log the response headers along with the minimal information. 354 """ 355 356 __slots__ = ( 357 "_token", 358 "_session", 359 "_lock", 360 "_max_retries", 361 "_client_secret", 362 "_client_id", 363 "_metadata", 364 "_dumps", 365 "_loads", 366 ) 367 368 def __init__( 369 self, 370 token: str, 371 /, 372 *, 373 client_secret: typing.Optional[str] = None, 374 client_id: typing.Optional[int] = None, 375 client_session: typing.Optional[aiohttp.ClientSession] = None, 376 dumps: typedefs.Dumps = helpers.dumps, 377 loads: typedefs.Loads = helpers.loads, 378 max_retries: int = 4, 379 enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False, 380 ) -> None: 381 self._session: typing.Optional[aiohttp.ClientSession] = client_session 382 self._lock: typing.Optional[asyncio.Lock] = None 383 self._client_secret = client_secret 384 self._client_id = client_id 385 self._token: str = token 386 self._max_retries = max_retries 387 self._dumps = dumps 388 self._loads = loads 389 self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {} 390 391 self._set_debug_level(enable_debugging) 392 393 @property 394 def client_id(self) -> typing.Optional[int]: 395 return self._client_id 396 397 @property 398 def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]: 399 return self._metadata 400 401 @property 402 def is_alive(self) -> bool: 403 return self._session is not None 404 405 @typing.final 406 async def close(self) -> None: 407 if self._session is None: 408 raise RuntimeError("REST client is not running.") 409 410 await self._session.close() 411 self._session = None 412 413 @typing.final 414 def open(self) -> None: 415 """Open a new client session. This is called internally with contextmanager usage.""" 416 if self._session: 417 raise RuntimeError("Cannot open REST client when it's already open.") 418 419 self._session = aiohttp.ClientSession( 420 connector=aiohttp.TCPConnector(), 421 connector_owner=True, 422 raise_for_status=False, 423 timeout=aiohttp.ClientTimeout(total=30.0), 424 ) 425 426 @typing.final 427 def enable_debugging( 428 self, 429 level: typing.Union[typing.Literal["TRACE"], bool, int] = False, 430 file: typing.Optional[typing.Union[pathlib.Path, str]] = None, 431 /, 432 ) -> None: 433 self._set_debug_level(level, file) 434 435 @typing.final 436 async def static_request( 437 self, 438 method: typing.Union[RequestMethod, str], 439 path: str, 440 *, 441 auth: typing.Optional[str] = None, 442 json: typing.Optional[dict[str, typing.Any]] = None, 443 ) -> ResponseSig: 444 return await self._request(method, path, auth=auth, json=json) 445 446 @typing.final 447 def build_oauth2_url( 448 self, client_id: typing.Optional[int] = None 449 ) -> typing.Optional[builders.OAuthURL]: 450 client_id = client_id or self._client_id 451 if client_id is None: 452 return None 453 454 return builders.OAuthURL(client_id=client_id) 455 456 @staticmethod 457 def _set_debug_level( 458 level: typing.Union[typing.Literal["TRACE"], bool, int] = False, 459 file: typing.Optional[typing.Union[pathlib.Path, str]] = None, 460 ) -> None: 461 file_handler = logging.FileHandler(file, mode="w") if file else None 462 if level == "TRACE" or level == TRACE: 463 logging.basicConfig( 464 level=TRACE, handlers=[file_handler] if file_handler else None 465 ) 466 467 elif level: 468 logging.basicConfig( 469 level=logging.DEBUG, handlers=[file_handler] if file_handler else None 470 ) 471 472 async def _request( 473 self, 474 method: typing.Union[RequestMethod, str], 475 route: str, 476 *, 477 base: bool = False, 478 oauth2: bool = False, 479 auth: typing.Optional[str] = None, 480 unwrapping: typing.Literal["json", "read"] = "json", 481 json: typing.Optional[dict[str, typing.Any] | str] = None, 482 headers: typing.Optional[dict[str, typing.Any]] = None, 483 ) -> ResponseSig: 484 # This is not None when opening the client. 485 assert self._session is not None 486 487 retries: int = 0 488 headers = headers or {} 489 490 headers.setdefault(_USER_AGENT_HEADERS, _USER_AGENT) 491 headers["X-API-KEY"] = self._token 492 493 if auth is not None: 494 headers[_AUTH_HEADER] = f"Bearer {auth}" 495 496 # Handling endpoints 497 endpoint = url.BASE 498 499 if not base: 500 endpoint = endpoint + url.REST_EP 501 502 if oauth2: 503 headers["Content-Type"] = "application/x-www-form-urlencoded" 504 endpoint = endpoint + url.TOKEN_EP 505 506 if self._lock is None: 507 self._lock = asyncio.Lock() 508 509 while True: 510 async with (stack := contextlib.AsyncExitStack()): 511 await stack.enter_async_context(self._lock) 512 513 data = self._dumps(json) if isinstance(json, dict) else json 514 # We make the request here. 515 taken_time = time.monotonic() 516 response = await self._session.request( 517 method=method, url=f"{endpoint}/{route}", headers=headers, data=data 518 ) 519 response_time = (time.monotonic() - taken_time) * 1_000 520 521 _LOG.debug( 522 "%s %s %s Time %.4fms", 523 method, 524 f"{endpoint}/{route}", 525 f"{response.status} {response.reason}", 526 response_time, 527 ) 528 529 await self._handle_ratelimit(response, method, route) 530 531 if response.status == http.HTTPStatus.NO_CONTENT: 532 return None 533 534 if 300 > response.status >= 200: 535 if unwrapping == "read": 536 # We need to read the bytes for the manifest response. 537 return await response.read() 538 539 if response.content_type == _APP_JSON: 540 # json_data = self._loads(await response.read()) 541 json_data = self._loads(await response.read()) 542 543 _LOG.debug( 544 "%s %s %s Time %.4fms", 545 method, 546 f"{endpoint}/{route}", 547 f"{response.status} {response.reason}", 548 response_time, 549 ) 550 551 if _LOG.isEnabledFor(TRACE): 552 cloned = headers.copy() 553 cloned.update(response.headers) # type: ignore 554 555 _LOG.log( 556 TRACE, 557 "%s", 558 error.stringify_http_message(cloned), 559 ) 560 561 # Return the response. 562 # oauth2 responses are not packed inside a Response object. 563 if oauth2: 564 return json_data # type: ignore[no-any-return] 565 566 return json_data["Response"] # type: ignore 567 568 if ( 569 response.status in _RETRY_5XX and retries < self._max_retries # noqa: W503 570 ): 571 backoff_ = backoff.ExponentialBackOff(maximum=6) 572 sleep_time = next(backoff_) 573 _LOG.warning( 574 "Got %i - %s. Sleeping for %.2f seconds. Remaining retries: %i", 575 response.status, 576 response.reason, 577 sleep_time, 578 self._max_retries - retries, 579 ) 580 581 retries += 1 582 await asyncio.sleep(sleep_time) 583 continue 584 585 raise await error.raise_error(response) 586 587 if not typing.TYPE_CHECKING: 588 589 def __enter__(self) -> typing.NoReturn: 590 cls = type(self) 591 raise TypeError( 592 f"{cls.__qualname__} is async only, use 'async with' instead." 593 ) 594 595 def __exit__( 596 self, 597 exception_type: typing.Optional[type[BaseException]], 598 exception: typing.Optional[BaseException], 599 exception_traceback: typing.Optional[types.TracebackType], 600 ) -> None: 601 ... 602 603 async def __aenter__(self) -> RESTClient: 604 self.open() 605 return self 606 607 async def __aexit__( 608 self, 609 exception_type: typing.Optional[type[BaseException]], 610 exception: typing.Optional[BaseException], 611 exception_traceback: typing.Optional[types.TracebackType], 612 ) -> None: 613 await self.close() 614 615 # We don't want this to be super complicated. 616 @typing.final 617 async def _handle_ratelimit( 618 self, 619 response: aiohttp.ClientResponse, 620 method: str, 621 route: str, 622 ) -> None: 623 if response.status != http.HTTPStatus.TOO_MANY_REQUESTS: 624 return 625 626 if response.content_type != _APP_JSON: 627 raise error.HTTPError( 628 f"Being ratelimited on non JSON request, {response.content_type}.", 629 http.HTTPStatus.TOO_MANY_REQUESTS, 630 ) 631 632 json: typedefs.JSONObject = self._loads(await response.read()) # type: ignore 633 retry_after = float(json.get("ThrottleSeconds", 15.0)) + 0.1 634 max_calls: int = 0 635 636 while True: 637 if max_calls == 10: 638 # Max retries by default. We raise an error here. 639 raise error.RateLimitedError( 640 body=json, 641 url=str(response.real_url), 642 retry_after=retry_after, 643 ) 644 645 # We sleep for a little bit to avoid funky behavior. 646 _LOG.warning( 647 "We're being ratelimited, Method %s Route %s. Sleeping for %.2fs.", 648 method, 649 route, 650 retry_after, 651 ) 652 await asyncio.sleep(retry_after) 653 max_calls += 1 654 continue 655 656 async def fetch_oauth2_tokens(self, code: str, /) -> builders.OAuth2Response: 657 if not isinstance(self._client_secret, (str, int)): 658 raise TypeError( 659 "Expected (str, int) for client secret " 660 f"but got {type(self._client_secret).__name__}" # type: ignore 661 ) 662 663 headers = { 664 "client_secret": self._client_secret, 665 } 666 667 data = ( 668 f"grant_type=authorization_code&code={code}" 669 f"&client_id={self._client_id}&client_secret={self._client_secret}" 670 ) 671 672 response = await self._request( 673 RequestMethod.POST, "", headers=headers, json=data, oauth2=True 674 ) 675 assert isinstance(response, dict) 676 return builders.OAuth2Response.build_response(response) 677 678 async def refresh_access_token( 679 self, refresh_token: str, / 680 ) -> builders.OAuth2Response: 681 if not isinstance(self._client_secret, (int, str)): 682 raise TypeError( 683 f"Expected (str, int) for client secret but got {type(self._client_secret).__name__}" # type: ignore 684 ) 685 686 data = { 687 "grant_type": "refresh_token", 688 "refresh_token": refresh_token, 689 "client_id": self._client_id, 690 "client_secret": self._client_secret, 691 "Content-Type": "application/x-www-form-urlencoded", 692 } 693 694 response = await self._request(RequestMethod.POST, "", json=data, oauth2=True) 695 assert isinstance(response, dict) 696 return builders.OAuth2Response.build_response(response) 697 698 async def fetch_bungie_user(self, id: int) -> typedefs.JSONObject: 699 resp = await self._request( 700 RequestMethod.GET, f"User/GetBungieNetUserById/{id}/" 701 ) 702 assert isinstance(resp, dict) 703 return resp 704 705 async def fetch_user_themes(self) -> typedefs.JSONArray: 706 resp = await self._request(RequestMethod.GET, "User/GetAvailableThemes/") 707 assert isinstance(resp, list) 708 return resp 709 710 async def fetch_membership_from_id( 711 self, 712 id: int, 713 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 714 /, 715 ) -> typedefs.JSONObject: 716 resp = await self._request( 717 RequestMethod.GET, f"User/GetMembershipsById/{id}/{int(type)}" 718 ) 719 assert isinstance(resp, dict) 720 return resp 721 722 async def fetch_player( 723 self, 724 name: str, 725 code: int, 726 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL, 727 /, 728 ) -> typedefs.JSONArray: 729 resp = await self._request( 730 RequestMethod.POST, 731 f"Destiny2/SearchDestinyPlayerByBungieName/{int(type)}", 732 json={"displayName": name, "displayNameCode": code}, 733 ) 734 assert isinstance(resp, list) 735 return resp 736 737 async def search_users(self, name: str, /) -> typedefs.JSONObject: 738 resp = await self._request( 739 RequestMethod.POST, 740 "User/Search/GlobalName/0", 741 json={"displayNamePrefix": name}, 742 ) 743 assert isinstance(resp, dict) 744 return resp 745 746 async def fetch_clan_from_id( 747 self, id: int, /, access_token: typing.Optional[str] = None 748 ) -> typedefs.JSONObject: 749 resp = await self._request( 750 RequestMethod.GET, f"GroupV2/{id}", auth=access_token 751 ) 752 assert isinstance(resp, dict) 753 return resp 754 755 async def fetch_clan( 756 self, 757 name: str, 758 /, 759 access_token: typing.Optional[str] = None, 760 *, 761 type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 762 ) -> typedefs.JSONObject: 763 resp = await self._request( 764 RequestMethod.GET, f"GroupV2/Name/{name}/{int(type)}", auth=access_token 765 ) 766 assert isinstance(resp, dict) 767 return resp 768 769 async def fetch_clan_admins(self, clan_id: int, /) -> typedefs.JSONObject: 770 resp = await self._request( 771 RequestMethod.GET, f"GroupV2/{clan_id}/AdminsAndFounder/" 772 ) 773 assert isinstance(resp, dict) 774 return resp 775 776 async def fetch_clan_conversations(self, clan_id: int, /) -> typedefs.JSONArray: 777 resp = await self._request( 778 RequestMethod.GET, f"GroupV2/{clan_id}/OptionalConversations/" 779 ) 780 assert isinstance(resp, list) 781 return resp 782 783 async def fetch_application(self, appid: int, /) -> typedefs.JSONObject: 784 resp = await self._request(RequestMethod.GET, f"App/Application/{appid}") 785 assert isinstance(resp, dict) 786 return resp 787 788 async def fetch_character( 789 self, 790 member_id: int, 791 membership_type: typedefs.IntAnd[enums.MembershipType], 792 character_id: int, 793 components: list[enums.ComponentType], 794 auth: typing.Optional[str] = None, 795 ) -> typedefs.JSONObject: 796 collector = _collect_components(components) 797 response = await self._request( 798 RequestMethod.GET, 799 f"Destiny2/{int(membership_type)}/Profile/{member_id}/" 800 f"Character/{character_id}/?components={collector}", 801 auth=auth, 802 ) 803 assert isinstance(response, dict) 804 return response 805 806 async def fetch_activities( 807 self, 808 member_id: int, 809 character_id: int, 810 mode: typedefs.IntAnd[enums.GameMode], 811 membership_type: typedefs.IntAnd[ 812 enums.MembershipType 813 ] = enums.MembershipType.ALL, 814 *, 815 page: int = 0, 816 limit: int = 1, 817 ) -> typedefs.JSONObject: 818 resp = await self._request( 819 RequestMethod.GET, 820 f"Destiny2/{int(membership_type)}/Account/" 821 f"{member_id}/Character/{character_id}/Stats/Activities" 822 f"/?mode={int(mode)}&count={limit}&page={page}", 823 ) 824 assert isinstance(resp, dict) 825 return resp 826 827 async def fetch_vendor_sales(self) -> typedefs.JSONObject: 828 resp = await self._request( 829 RequestMethod.GET, 830 f"Destiny2/Vendors/?components={int(enums.ComponentType.VENDOR_SALES)}", 831 ) 832 assert isinstance(resp, dict) 833 return resp 834 835 async def fetch_profile( 836 self, 837 membership_id: int, 838 type: typedefs.IntAnd[enums.MembershipType], 839 components: list[enums.ComponentType], 840 auth: typing.Optional[str] = None, 841 ) -> typedefs.JSONObject: 842 collector = _collect_components(components) 843 response = await self._request( 844 RequestMethod.GET, 845 f"Destiny2/{int(type)}/Profile/{membership_id}/?components={collector}", 846 auth=auth, 847 ) 848 assert isinstance(response, dict) 849 return response 850 851 async def fetch_entity(self, type: str, hash: int) -> typedefs.JSONObject: 852 response = await self._request( 853 RequestMethod.GET, route=f"Destiny2/Manifest/{type}/{hash}" 854 ) 855 assert isinstance(response, dict) 856 return response 857 858 async def fetch_inventory_item(self, hash: int, /) -> typedefs.JSONObject: 859 resp = await self.fetch_entity("DestinyInventoryItemDefinition", hash) 860 assert isinstance(resp, dict) 861 return resp 862 863 async def fetch_objective_entity(self, hash: int, /) -> typedefs.JSONObject: 864 resp = await self.fetch_entity("DestinyObjectiveDefinition", hash) 865 assert isinstance(resp, dict) 866 return resp 867 868 async def fetch_groups_for_member( 869 self, 870 member_id: int, 871 member_type: typedefs.IntAnd[enums.MembershipType], 872 /, 873 *, 874 filter: int = 0, 875 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 876 ) -> typedefs.JSONObject: 877 resp = await self._request( 878 RequestMethod.GET, 879 f"GroupV2/User/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/", 880 ) 881 assert isinstance(resp, dict) 882 return resp 883 884 async def fetch_potential_groups_for_member( 885 self, 886 member_id: int, 887 member_type: typedefs.IntAnd[enums.MembershipType], 888 /, 889 *, 890 filter: int = 0, 891 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 892 ) -> typedefs.JSONObject: 893 resp = await self._request( 894 RequestMethod.GET, 895 f"GroupV2/User/Potential/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/", 896 ) 897 assert isinstance(resp, dict) 898 return resp 899 900 async def fetch_clan_members( 901 self, 902 clan_id: int, 903 /, 904 *, 905 name: typing.Optional[str] = None, 906 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 907 ) -> typedefs.JSONObject: 908 resp = await self._request( 909 RequestMethod.GET, 910 f"/GroupV2/{clan_id}/Members/?memberType={int(type)}&nameSearch={name if name else ''}¤tpage=1", 911 ) 912 assert isinstance(resp, dict) 913 return resp 914 915 async def fetch_hardlinked_credentials( 916 self, 917 credential: int, 918 type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID, 919 /, 920 ) -> typedefs.JSONObject: 921 resp = await self._request( 922 RequestMethod.GET, 923 f"User/GetMembershipFromHardLinkedCredential/{int(type)}/{credential}/", 924 ) 925 assert isinstance(resp, dict) 926 return resp 927 928 async def fetch_user_credentials( 929 self, access_token: str, membership_id: int, / 930 ) -> typedefs.JSONArray: 931 resp = await self._request( 932 RequestMethod.GET, 933 f"User/GetCredentialTypesForTargetAccount/{membership_id}", 934 auth=access_token, 935 ) 936 assert isinstance(resp, list) 937 return resp 938 939 async def insert_socket_plug( 940 self, 941 action_token: str, 942 /, 943 instance_id: int, 944 plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]], 945 character_id: int, 946 membership_type: typedefs.IntAnd[enums.MembershipType], 947 ) -> typedefs.JSONObject: 948 if isinstance(plug, builders.PlugSocketBuilder): 949 plug = plug.collect() 950 951 body = { 952 "actionToken": action_token, 953 "itemInstanceId": instance_id, 954 "plug": plug, 955 "characterId": character_id, 956 "membershipType": int(membership_type), 957 } 958 resp = await self._request( 959 RequestMethod.POST, "Destiny2/Actions/Items/InsertSocketPlug", json=body 960 ) 961 assert isinstance(resp, dict) 962 return resp 963 964 async def insert_socket_plug_free( 965 self, 966 access_token: str, 967 /, 968 instance_id: int, 969 plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]], 970 character_id: int, 971 membership_type: typedefs.IntAnd[enums.MembershipType], 972 ) -> typedefs.JSONObject: 973 if isinstance(plug, builders.PlugSocketBuilder): 974 plug = plug.collect() 975 976 body = { 977 "itemInstanceId": instance_id, 978 "plug": plug, 979 "characterId": character_id, 980 "membershipType": int(membership_type), 981 } 982 resp = await self._request( 983 RequestMethod.POST, 984 "Destiny2/Actions/Items/InsertSocketPlugFree", 985 json=body, 986 auth=access_token, 987 ) 988 assert isinstance(resp, dict) 989 return resp 990 991 async def set_item_lock_state( 992 self, 993 access_token: str, 994 state: bool, 995 /, 996 item_id: int, 997 character_id: int, 998 membership_type: typedefs.IntAnd[enums.MembershipType], 999 ) -> int: 1000 body = { 1001 "state": state, 1002 "itemId": item_id, 1003 "characterId": character_id, 1004 "membershipType": int(membership_type), 1005 } 1006 response = await self._request( 1007 RequestMethod.POST, 1008 "Destiny2/Actions/Items/SetLockState", 1009 json=body, 1010 auth=access_token, 1011 ) 1012 assert isinstance(response, int) 1013 return response 1014 1015 async def set_quest_track_state( 1016 self, 1017 access_token: str, 1018 state: bool, 1019 /, 1020 item_id: int, 1021 character_id: int, 1022 membership_type: typedefs.IntAnd[enums.MembershipType], 1023 ) -> int: 1024 body = { 1025 "state": state, 1026 "itemId": item_id, 1027 "characterId": character_id, 1028 "membership_type": int(membership_type), 1029 } 1030 response = await self._request( 1031 RequestMethod.POST, 1032 "Destiny2/Actions/Items/SetTrackedState", 1033 json=body, 1034 auth=access_token, 1035 ) 1036 assert isinstance(response, int) 1037 return response 1038 1039 async def fetch_manifest_path(self) -> typedefs.JSONObject: 1040 path = await self._request(RequestMethod.GET, "Destiny2/Manifest") 1041 assert isinstance(path, dict) 1042 return path 1043 1044 async def read_manifest_bytes(self, language: str = "en", /) -> bytes: 1045 _ensure_manifest_language(language) 1046 1047 content = await self.fetch_manifest_path() 1048 resp = await self._request( 1049 RequestMethod.GET, 1050 content["mobileWorldContentPaths"][language], 1051 unwrapping="read", 1052 base=True, 1053 ) 1054 assert isinstance(resp, bytes) 1055 return resp 1056 1057 async def download_manifest( 1058 self, 1059 language: str = "en", 1060 name: str = "manifest", 1061 path: typing.Union[pathlib.Path, str] = ".", 1062 *, 1063 force: bool = False, 1064 ) -> None: 1065 complete_path = _get_path(name, path, sql=True) 1066 1067 if complete_path.exists() and force: 1068 if force: 1069 _LOG.info( 1070 f"Found manifest in {complete_path!s}. Forcing to Re-Download." 1071 ) 1072 complete_path.unlink(missing_ok=True) 1073 1074 return await self.download_manifest(language, name, path, force=force) 1075 1076 else: 1077 raise FileExistsError( 1078 "Manifest file already exists, " 1079 "To force download, set the `force` parameter to `True`." 1080 ) 1081 1082 _LOG.info(f"Downloading manifest. Location: {complete_path!s}") 1083 data_bytes = await self.read_manifest_bytes(language) 1084 await asyncio.get_running_loop().run_in_executor( 1085 None, _write_sqlite_bytes, data_bytes, path, name 1086 ) 1087 1088 async def download_json_manifest( 1089 self, 1090 file_name: str = "manifest", 1091 path: typing.Union[str, pathlib.Path] = ".", 1092 language: str = "en", 1093 ) -> None: 1094 _ensure_manifest_language(language) 1095 1096 _LOG.info(f"Downloading manifest JSON to {_get_path(file_name, path)!r}...") 1097 1098 content = await self.fetch_manifest_path() 1099 json_bytes = await self._request( 1100 RequestMethod.GET, 1101 content["jsonWorldContentPaths"][language], 1102 unwrapping="read", 1103 base=True, 1104 ) 1105 1106 await asyncio.get_running_loop().run_in_executor( 1107 None, _write_json_bytes, json_bytes, file_name, path 1108 ) 1109 _LOG.info("Finished downloading manifest JSON.") 1110 1111 async def fetch_manifest_version(self) -> str: 1112 return typing.cast(str, (await self.fetch_manifest_path())["version"]) 1113 1114 async def fetch_linked_profiles( 1115 self, 1116 member_id: int, 1117 member_type: typedefs.IntAnd[enums.MembershipType], 1118 /, 1119 *, 1120 all: bool = False, 1121 ) -> typedefs.JSONObject: 1122 resp = await self._request( 1123 RequestMethod.GET, 1124 f"Destiny2/{int(member_type)}/Profile/{member_id}/LinkedProfiles/?getAllMemberships={all}", 1125 ) 1126 assert isinstance(resp, dict) 1127 return resp 1128 1129 async def fetch_clan_banners(self) -> typedefs.JSONObject: 1130 resp = await self._request( 1131 RequestMethod.GET, "Destiny2/Clan/ClanBannerDictionary/" 1132 ) 1133 assert isinstance(resp, dict) 1134 return resp 1135 1136 async def fetch_public_milestones(self) -> typedefs.JSONObject: 1137 resp = await self._request(RequestMethod.GET, "Destiny2/Milestones/") 1138 assert isinstance(resp, dict) 1139 return resp 1140 1141 async def fetch_public_milestone_content( 1142 self, milestone_hash: int, / 1143 ) -> typedefs.JSONObject: 1144 resp = await self._request( 1145 RequestMethod.GET, f"Destiny2/Milestones/{milestone_hash}/Content/" 1146 ) 1147 assert isinstance(resp, dict) 1148 return resp 1149 1150 async def fetch_current_user_memberships( 1151 self, access_token: str, / 1152 ) -> typedefs.JSONObject: 1153 resp = await self._request( 1154 RequestMethod.GET, 1155 "User/GetMembershipsForCurrentUser/", 1156 auth=access_token, 1157 ) 1158 assert isinstance(resp, dict) 1159 return resp 1160 1161 async def equip_item( 1162 self, 1163 access_token: str, 1164 /, 1165 item_id: int, 1166 character_id: int, 1167 membership_type: typedefs.IntAnd[enums.MembershipType], 1168 ) -> None: 1169 payload = { 1170 "itemId": item_id, 1171 "characterId": character_id, 1172 "membershipType": int(membership_type), 1173 } 1174 1175 await self._request( 1176 RequestMethod.POST, 1177 "Destiny2/Actions/Items/EquipItem/", 1178 json=payload, 1179 auth=access_token, 1180 ) 1181 1182 async def equip_items( 1183 self, 1184 access_token: str, 1185 /, 1186 item_ids: list[int], 1187 character_id: int, 1188 membership_type: typedefs.IntAnd[enums.MembershipType], 1189 ) -> None: 1190 payload = { 1191 "itemIds": item_ids, 1192 "characterId": character_id, 1193 "membershipType": int(membership_type), 1194 } 1195 await self._request( 1196 RequestMethod.POST, 1197 "Destiny2/Actions/Items/EquipItems/", 1198 json=payload, 1199 auth=access_token, 1200 ) 1201 1202 async def ban_clan_member( 1203 self, 1204 access_token: str, 1205 /, 1206 group_id: int, 1207 membership_id: int, 1208 membership_type: typedefs.IntAnd[enums.MembershipType], 1209 *, 1210 length: int = 0, 1211 comment: undefined.UndefinedOr[str] = undefined.UNDEFINED, 1212 ) -> None: 1213 payload = {"comment": str(comment), "length": length} 1214 await self._request( 1215 RequestMethod.POST, 1216 f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Ban/", 1217 json=payload, 1218 auth=access_token, 1219 ) 1220 1221 async def unban_clan_member( 1222 self, 1223 access_token: str, 1224 /, 1225 group_id: int, 1226 membership_id: int, 1227 membership_type: typedefs.IntAnd[enums.MembershipType], 1228 ) -> None: 1229 await self._request( 1230 RequestMethod.POST, 1231 f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Unban/", 1232 auth=access_token, 1233 ) 1234 1235 async def kick_clan_member( 1236 self, 1237 access_token: str, 1238 /, 1239 group_id: int, 1240 membership_id: int, 1241 membership_type: typedefs.IntAnd[enums.MembershipType], 1242 ) -> typedefs.JSONObject: 1243 resp = await self._request( 1244 RequestMethod.POST, 1245 f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Kick/", 1246 auth=access_token, 1247 ) 1248 assert isinstance(resp, dict) 1249 return resp 1250 1251 async def edit_clan( 1252 self, 1253 access_token: str, 1254 /, 1255 group_id: int, 1256 *, 1257 name: typedefs.NoneOr[str] = None, 1258 about: typedefs.NoneOr[str] = None, 1259 motto: typedefs.NoneOr[str] = None, 1260 theme: typedefs.NoneOr[str] = None, 1261 tags: typedefs.NoneOr[collections.Sequence[str]] = None, 1262 is_public: typedefs.NoneOr[bool] = None, 1263 locale: typedefs.NoneOr[str] = None, 1264 avatar_image_index: typedefs.NoneOr[int] = None, 1265 membership_option: typedefs.NoneOr[ 1266 typedefs.IntAnd[enums.MembershipOption] 1267 ] = None, 1268 allow_chat: typedefs.NoneOr[bool] = None, 1269 chat_security: typedefs.NoneOr[typing.Literal[0, 1]] = None, 1270 call_sign: typedefs.NoneOr[str] = None, 1271 homepage: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None, 1272 enable_invite_messaging_for_admins: typedefs.NoneOr[bool] = None, 1273 default_publicity: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None, 1274 is_public_topic_admin: typedefs.NoneOr[bool] = None, 1275 ) -> None: 1276 payload = { 1277 "name": name, 1278 "about": about, 1279 "motto": motto, 1280 "theme": theme, 1281 "tags": tags, 1282 "isPublic": is_public, 1283 "avatarImageIndex": avatar_image_index, 1284 "isPublicTopicAdminOnly": is_public_topic_admin, 1285 "allowChat": allow_chat, 1286 "chatSecurity": chat_security, 1287 "callsign": call_sign, 1288 "homepage": homepage, 1289 "enableInvitationMessagingForAdmins": enable_invite_messaging_for_admins, 1290 "defaultPublicity": default_publicity, 1291 "locale": locale, 1292 } 1293 if membership_option is not None: 1294 payload["membershipOption"] = int(membership_option) 1295 1296 await self._request( 1297 RequestMethod.POST, 1298 f"GroupV2/{group_id}/Edit", 1299 json=payload, 1300 auth=access_token, 1301 ) 1302 1303 async def edit_clan_options( 1304 self, 1305 access_token: str, 1306 /, 1307 group_id: int, 1308 *, 1309 invite_permissions_override: typedefs.NoneOr[bool] = None, 1310 update_culture_permissionOverride: typedefs.NoneOr[bool] = None, 1311 host_guided_game_permission_override: typedefs.NoneOr[ 1312 typing.Literal[0, 1, 2] 1313 ] = None, 1314 update_banner_permission_override: typedefs.NoneOr[bool] = None, 1315 join_level: typedefs.NoneOr[typedefs.IntAnd[enums.ClanMemberType]] = None, 1316 ) -> None: 1317 payload = { 1318 "InvitePermissionOverride": invite_permissions_override, 1319 "UpdateCulturePermissionOverride": update_culture_permissionOverride, 1320 "HostGuidedGamePermissionOverride": host_guided_game_permission_override, 1321 "UpdateBannerPermissionOverride": update_banner_permission_override, 1322 "JoinLevel": int(join_level) if join_level else None, 1323 } 1324 1325 await self._request( 1326 RequestMethod.POST, 1327 f"GroupV2/{group_id}/EditFounderOptions", 1328 json=payload, 1329 auth=access_token, 1330 ) 1331 1332 async def fetch_friends(self, access_token: str, /) -> typedefs.JSONObject: 1333 resp = await self._request( 1334 RequestMethod.GET, 1335 "Social/Friends/", 1336 auth=access_token, 1337 ) 1338 assert isinstance(resp, dict) 1339 return resp 1340 1341 async def fetch_friend_requests(self, access_token: str, /) -> typedefs.JSONObject: 1342 resp = await self._request( 1343 RequestMethod.GET, 1344 "Social/Friends/Requests", 1345 auth=access_token, 1346 ) 1347 assert isinstance(resp, dict) 1348 return resp 1349 1350 async def accept_friend_request(self, access_token: str, /, member_id: int) -> None: 1351 await self._request( 1352 RequestMethod.POST, 1353 f"Social/Friends/Requests/Accept/{member_id}", 1354 auth=access_token, 1355 ) 1356 1357 async def send_friend_request(self, access_token: str, /, member_id: int) -> None: 1358 await self._request( 1359 RequestMethod.POST, 1360 f"Social/Friends/Add/{member_id}", 1361 auth=access_token, 1362 ) 1363 1364 async def decline_friend_request( 1365 self, access_token: str, /, member_id: int 1366 ) -> None: 1367 await self._request( 1368 RequestMethod.POST, 1369 f"Social/Friends/Requests/Decline/{member_id}", 1370 auth=access_token, 1371 ) 1372 1373 async def remove_friend(self, access_token: str, /, member_id: int) -> None: 1374 await self._request( 1375 RequestMethod.POST, 1376 f"Social/Friends/Remove/{member_id}", 1377 auth=access_token, 1378 ) 1379 1380 async def remove_friend_request(self, access_token: str, /, member_id: int) -> None: 1381 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1382 await self._request( 1383 RequestMethod.POST, 1384 f"Social/Friends/Requests/Remove/{member_id}", 1385 auth=access_token, 1386 ) 1387 1388 async def approve_all_pending_group_users( 1389 self, 1390 access_token: str, 1391 /, 1392 group_id: int, 1393 message: undefined.UndefinedOr[str] = undefined.UNDEFINED, 1394 ) -> None: 1395 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1396 await self._request( 1397 RequestMethod.POST, 1398 f"GroupV2/{group_id}/Members/ApproveAll", 1399 auth=access_token, 1400 json={"message": str(message)}, 1401 ) 1402 1403 async def deny_all_pending_group_users( 1404 self, 1405 access_token: str, 1406 /, 1407 group_id: int, 1408 *, 1409 message: undefined.UndefinedOr[str] = undefined.UNDEFINED, 1410 ) -> None: 1411 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1412 await self._request( 1413 RequestMethod.POST, 1414 f"GroupV2/{group_id}/Members/DenyAll", 1415 auth=access_token, 1416 json={"message": str(message)}, 1417 ) 1418 1419 async def add_optional_conversation( 1420 self, 1421 access_token: str, 1422 /, 1423 group_id: int, 1424 *, 1425 name: undefined.UndefinedOr[str] = undefined.UNDEFINED, 1426 security: typing.Literal[0, 1] = 0, 1427 ) -> None: 1428 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1429 payload = {"chatName": str(name), "chatSecurity": security} 1430 await self._request( 1431 RequestMethod.POST, 1432 f"GroupV2/{group_id}/OptionalConversations/Add", 1433 json=payload, 1434 auth=access_token, 1435 ) 1436 1437 async def edit_optional_conversation( 1438 self, 1439 access_token: str, 1440 /, 1441 group_id: int, 1442 conversation_id: int, 1443 *, 1444 name: undefined.UndefinedOr[str] = undefined.UNDEFINED, 1445 security: typing.Literal[0, 1] = 0, 1446 enable_chat: bool = False, 1447 ) -> None: 1448 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1449 payload = { 1450 "chatEnabled": enable_chat, 1451 "chatName": str(name), 1452 "chatSecurity": security, 1453 } 1454 await self._request( 1455 RequestMethod.POST, 1456 f"GroupV2/{group_id}/OptionalConversations/Edit/{conversation_id}", 1457 json=payload, 1458 auth=access_token, 1459 ) 1460 1461 async def transfer_item( 1462 self, 1463 access_token: str, 1464 /, 1465 item_id: int, 1466 item_hash: int, 1467 character_id: int, 1468 member_type: typedefs.IntAnd[enums.MembershipType], 1469 *, 1470 stack_size: int = 1, 1471 vault: bool = False, 1472 ) -> None: 1473 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1474 payload = { 1475 "characterId": character_id, 1476 "membershipType": int(member_type), 1477 "itemId": item_id, 1478 "itemReferenceHash": item_hash, 1479 "stackSize": stack_size, 1480 "transferToVault": vault, 1481 } 1482 await self._request( 1483 RequestMethod.POST, 1484 "Destiny2/Actions/Items/TransferItem", 1485 json=payload, 1486 auth=access_token, 1487 ) 1488 1489 async def pull_item( 1490 self, 1491 access_token: str, 1492 /, 1493 item_id: int, 1494 item_hash: int, 1495 character_id: int, 1496 member_type: typedefs.IntAnd[enums.MembershipType], 1497 *, 1498 stack_size: int = 1, 1499 vault: bool = False, 1500 ) -> None: 1501 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1502 payload = { 1503 "characterId": character_id, 1504 "membershipType": int(member_type), 1505 "itemId": item_id, 1506 "itemReferenceHash": item_hash, 1507 "stackSize": stack_size, 1508 "transferToVault": vault, 1509 } 1510 await self._request( 1511 RequestMethod.POST, 1512 "Destiny2/Actions/Items/PullFromPostmaster", 1513 json=payload, 1514 auth=access_token, 1515 ) 1516 1517 async def fetch_fireteams( 1518 self, 1519 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 1520 *, 1521 platform: typedefs.IntAnd[ 1522 fireteams.FireteamPlatform 1523 ] = fireteams.FireteamPlatform.ANY, 1524 language: typing.Union[ 1525 fireteams.FireteamLanguage, str 1526 ] = fireteams.FireteamLanguage.ALL, 1527 date_range: typedefs.IntAnd[ 1528 fireteams.FireteamDate 1529 ] = fireteams.FireteamDate.ALL, 1530 page: int = 0, 1531 slots_filter: int = 0, 1532 ) -> typedefs.JSONObject: 1533 resp = await self._request( 1534 RequestMethod.GET, 1535 f"Fireteam/Search/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{page}/?langFilter={str(language)}", # noqa: E501 Line too long 1536 ) 1537 assert isinstance(resp, dict) 1538 return resp 1539 1540 async def fetch_available_clan_fireteams( 1541 self, 1542 access_token: str, 1543 group_id: int, 1544 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 1545 *, 1546 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1547 language: typing.Union[fireteams.FireteamLanguage, str], 1548 date_range: typedefs.IntAnd[ 1549 fireteams.FireteamDate 1550 ] = fireteams.FireteamDate.ALL, 1551 page: int = 0, 1552 public_only: bool = False, 1553 slots_filter: int = 0, 1554 ) -> typedefs.JSONObject: 1555 resp = await self._request( 1556 RequestMethod.GET, 1557 f"Fireteam/Clan/{group_id}/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{public_only}/{page}", # noqa: E501 1558 json={"langFilter": str(language)}, 1559 auth=access_token, 1560 ) 1561 assert isinstance(resp, dict) 1562 return resp 1563 1564 async def fetch_clan_fireteam( 1565 self, access_token: str, fireteam_id: int, group_id: int 1566 ) -> typedefs.JSONObject: 1567 resp = await self._request( 1568 RequestMethod.GET, 1569 f"Fireteam/Clan/{group_id}/Summary/{fireteam_id}", 1570 auth=access_token, 1571 ) 1572 assert isinstance(resp, dict) 1573 return resp 1574 1575 async def fetch_my_clan_fireteams( 1576 self, 1577 access_token: str, 1578 group_id: int, 1579 *, 1580 include_closed: bool = True, 1581 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1582 language: typing.Union[fireteams.FireteamLanguage, str], 1583 filtered: bool = True, 1584 page: int = 0, 1585 ) -> typedefs.JSONObject: 1586 payload = {"groupFilter": filtered, "langFilter": str(language)} 1587 1588 resp = await self._request( 1589 RequestMethod.GET, 1590 f"Fireteam/Clan/{group_id}/My/{int(platform)}/{include_closed}/{page}", 1591 json=payload, 1592 auth=access_token, 1593 ) 1594 assert isinstance(resp, dict) 1595 return resp 1596 1597 async def fetch_private_clan_fireteams( 1598 self, access_token: str, group_id: int, / 1599 ) -> int: 1600 resp = await self._request( 1601 RequestMethod.GET, 1602 f"Fireteam/Clan/{group_id}/ActiveCount", 1603 auth=access_token, 1604 ) 1605 assert isinstance(resp, int) 1606 return resp 1607 1608 async def fetch_post_activity(self, instance_id: int, /) -> typedefs.JSONObject: 1609 resp = await self._request( 1610 RequestMethod.GET, f"Destiny2/Stats/PostGameCarnageReport/{instance_id}" 1611 ) 1612 assert isinstance(resp, dict) 1613 return resp 1614 1615 async def search_entities( 1616 self, name: str, entity_type: str, *, page: int = 0 1617 ) -> typedefs.JSONObject: 1618 resp = await self._request( 1619 RequestMethod.GET, 1620 f"Destiny2/Armory/Search/{entity_type}/{name}/", 1621 json={"page": page}, 1622 ) 1623 assert isinstance(resp, dict) 1624 return resp 1625 1626 async def fetch_unique_weapon_history( 1627 self, 1628 membership_id: int, 1629 character_id: int, 1630 membership_type: typedefs.IntAnd[enums.MembershipType], 1631 ) -> typedefs.JSONObject: 1632 resp = await self._request( 1633 RequestMethod.GET, 1634 f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/UniqueWeapons/", 1635 ) 1636 assert isinstance(resp, dict) 1637 return resp 1638 1639 async def fetch_item( 1640 self, 1641 member_id: int, 1642 item_id: int, 1643 membership_type: typedefs.IntAnd[enums.MembershipType], 1644 components: list[enums.ComponentType], 1645 ) -> typedefs.JSONObject: 1646 collector = _collect_components(components) 1647 1648 resp = await self._request( 1649 RequestMethod.GET, 1650 f"Destiny2/{int(membership_type)}/Profile/{member_id}/Item/{item_id}/?components={collector}", 1651 ) 1652 assert isinstance(resp, dict) 1653 return resp 1654 1655 async def fetch_clan_weekly_rewards(self, clan_id: int, /) -> typedefs.JSONObject: 1656 resp = await self._request( 1657 RequestMethod.GET, f"Destiny2/Clan/{clan_id}/WeeklyRewardState/" 1658 ) 1659 assert isinstance(resp, dict) 1660 return resp 1661 1662 async def fetch_available_locales(self) -> typedefs.JSONObject: 1663 resp = await self._request( 1664 RequestMethod.GET, "Destiny2/Manifest/DestinyLocaleDefinition/" 1665 ) 1666 assert isinstance(resp, dict) 1667 return resp 1668 1669 async def fetch_common_settings(self) -> typedefs.JSONObject: 1670 resp = await self._request(RequestMethod.GET, "Settings") 1671 assert isinstance(resp, dict) 1672 return resp 1673 1674 async def fetch_user_systems_overrides(self) -> typedefs.JSONObject: 1675 resp = await self._request(RequestMethod.GET, "UserSystemOverrides") 1676 assert isinstance(resp, dict) 1677 return resp 1678 1679 async def fetch_global_alerts( 1680 self, *, include_streaming: bool = False 1681 ) -> typedefs.JSONArray: 1682 resp = await self._request( 1683 RequestMethod.GET, f"GlobalAlerts/?includestreaming={include_streaming}" 1684 ) 1685 assert isinstance(resp, list) 1686 return resp 1687 1688 async def awainitialize_request( 1689 self, 1690 access_token: str, 1691 type: typing.Literal[0, 1], 1692 membership_type: typedefs.IntAnd[enums.MembershipType], 1693 /, 1694 *, 1695 affected_item_id: typing.Optional[int] = None, 1696 character_id: typing.Optional[int] = None, 1697 ) -> typedefs.JSONObject: 1698 body = {"type": type, "membershipType": int(membership_type)} 1699 1700 if affected_item_id is not None: 1701 body["affectedItemId"] = affected_item_id 1702 1703 if character_id is not None: 1704 body["characterId"] = character_id 1705 1706 resp = await self._request( 1707 RequestMethod.POST, "Destiny2/Awa/Initialize", json=body, auth=access_token 1708 ) 1709 assert isinstance(resp, dict) 1710 return resp 1711 1712 async def awaget_action_token( 1713 self, access_token: str, correlation_id: str, / 1714 ) -> typedefs.JSONObject: 1715 resp = await self._request( 1716 RequestMethod.POST, 1717 f"Destiny2/Awa/GetActionToken/{correlation_id}", 1718 auth=access_token, 1719 ) 1720 assert isinstance(resp, dict) 1721 return resp 1722 1723 async def awa_provide_authorization_result( 1724 self, 1725 access_token: str, 1726 selection: int, 1727 correlation_id: str, 1728 nonce: collections.MutableSequence[typing.Union[str, bytes]], 1729 ) -> int: 1730 body = {"selection": selection, "correlationId": correlation_id, "nonce": nonce} 1731 1732 resp = await self._request( 1733 RequestMethod.POST, 1734 "Destiny2/Awa/AwaProvideAuthorizationResult", 1735 json=body, 1736 auth=access_token, 1737 ) 1738 assert isinstance(resp, int) 1739 return resp 1740 1741 async def fetch_vendors( 1742 self, 1743 access_token: str, 1744 character_id: int, 1745 membership_id: int, 1746 membership_type: typedefs.IntAnd[enums.MembershipType], 1747 /, 1748 components: list[enums.ComponentType], 1749 filter: typing.Optional[int] = None, 1750 ) -> typedefs.JSONObject: 1751 components_ = _collect_components(components) 1752 route = ( 1753 f"Destiny2/{int(membership_type)}/Profile/{membership_id}" 1754 f"/Character/{character_id}/Vendors/?components={components_}" 1755 ) 1756 1757 if filter is not None: 1758 route = route + f"&filter={filter}" 1759 1760 resp = await self._request( 1761 RequestMethod.GET, 1762 route, 1763 auth=access_token, 1764 ) 1765 assert isinstance(resp, dict) 1766 return resp 1767 1768 async def fetch_vendor( 1769 self, 1770 access_token: str, 1771 character_id: int, 1772 membership_id: int, 1773 membership_type: typedefs.IntAnd[enums.MembershipType], 1774 vendor_hash: int, 1775 /, 1776 components: list[enums.ComponentType], 1777 ) -> typedefs.JSONObject: 1778 components_ = _collect_components(components) 1779 resp = await self._request( 1780 RequestMethod.GET, 1781 ( 1782 f"Destiny2/{int(membership_type)}/Profile/{membership_id}" 1783 f"/Character/{character_id}/Vendors/{vendor_hash}/?components={components_}" 1784 ), 1785 auth=access_token, 1786 ) 1787 assert isinstance(resp, dict) 1788 return resp 1789 1790 async def fetch_application_api_usage( 1791 self, 1792 access_token: str, 1793 application_id: int, 1794 /, 1795 *, 1796 start: typing.Optional[datetime.datetime] = None, 1797 end: typing.Optional[datetime.datetime] = None, 1798 ) -> typedefs.JSONObject: 1799 end_date, start_date = time.parse_date_range(end, start) 1800 resp = await self._request( 1801 RequestMethod.GET, 1802 f"App/ApiUsage/{application_id}/?end={end_date}&start={start_date}", 1803 auth=access_token, 1804 ) 1805 assert isinstance(resp, dict) 1806 return resp 1807 1808 async def fetch_bungie_applications(self) -> typedefs.JSONArray: 1809 resp = await self._request(RequestMethod.GET, "App/FirstParty") 1810 assert isinstance(resp, list) 1811 return resp 1812 1813 async def fetch_content_type(self, type: str, /) -> typedefs.JSONObject: 1814 resp = await self._request(RequestMethod.GET, f"Content/GetContentType/{type}/") 1815 assert isinstance(resp, dict) 1816 return resp 1817 1818 async def fetch_content_by_id( 1819 self, id: int, locale: str, /, *, head: bool = False 1820 ) -> typedefs.JSONObject: 1821 resp = await self._request( 1822 RequestMethod.GET, 1823 f"Content/GetContentById/{id}/{locale}/", 1824 json={"head": head}, 1825 ) 1826 assert isinstance(resp, dict) 1827 return resp 1828 1829 async def fetch_content_by_tag_and_type( 1830 self, locale: str, tag: str, type: str, *, head: bool = False 1831 ) -> typedefs.JSONObject: 1832 resp = await self._request( 1833 RequestMethod.GET, 1834 f"Content/GetContentByTagAndType/{tag}/{type}/{locale}/", 1835 json={"head": head}, 1836 ) 1837 assert isinstance(resp, dict) 1838 return resp 1839 1840 async def search_content_with_text( 1841 self, 1842 locale: str, 1843 /, 1844 content_type: str, 1845 search_text: str, 1846 tag: str, 1847 *, 1848 page: undefined.UndefinedOr[int] = undefined.UNDEFINED, 1849 source: undefined.UndefinedOr[str] = undefined.UNDEFINED, 1850 ) -> typedefs.JSONObject: 1851 body: typedefs.JSONObject = {} 1852 1853 body["ctype"] = content_type 1854 body["searchtext"] = search_text 1855 body["tag"] = tag 1856 1857 if page is not undefined.UNDEFINED: 1858 body["currentpage"] = page 1859 else: 1860 body["currentpage"] = 1 1861 1862 if source is not undefined.UNDEFINED: 1863 body["source"] = source 1864 else: 1865 source = "" 1866 resp = await self._request( 1867 RequestMethod.GET, f"Content/Search/{locale}/", json=body 1868 ) 1869 assert isinstance(resp, dict) 1870 return resp 1871 1872 async def search_content_by_tag_and_type( 1873 self, 1874 locale: str, 1875 tag: str, 1876 type: str, 1877 *, 1878 page: undefined.UndefinedOr[int] = undefined.UNDEFINED, 1879 ) -> typedefs.JSONObject: 1880 body: typedefs.JSONObject = {} 1881 body["currentpage"] = 1 if page is undefined.UNDEFINED else page 1882 resp = await self._request( 1883 RequestMethod.GET, 1884 f"Content/SearchContentByTagAndType/{tag}/{type}/{locale}/", 1885 json=body, 1886 ) 1887 assert isinstance(resp, dict) 1888 return resp 1889 1890 async def search_help_articles( 1891 self, text: str, size: str, / 1892 ) -> typedefs.JSONObject: 1893 resp = await self._request( 1894 RequestMethod.GET, f"Content/SearchHelpArticles/{text}/{size}/" 1895 ) 1896 assert isinstance(resp, dict) 1897 return resp 1898 1899 async def fetch_topics_page( 1900 self, 1901 category_filter: int, 1902 group: int, 1903 date_filter: int, 1904 sort: typing.Union[str, bytes], 1905 *, 1906 page: undefined.UndefinedOr[int] = undefined.UNDEFINED, 1907 locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.UNDEFINED, 1908 tag_filter: undefined.UndefinedOr[str] = undefined.UNDEFINED, 1909 ) -> typedefs.JSONObject: 1910 body: typedefs.JSONObject = {} 1911 if locales is not undefined.UNDEFINED: 1912 body["locales"] = ",".join(str(locales)) 1913 else: 1914 body["locales"] = ",".join([]) 1915 1916 if tag_filter is not undefined.UNDEFINED: 1917 body["tagstring"] = tag_filter 1918 else: 1919 body["tagstring"] = "" 1920 1921 page = 0 if page is not undefined.UNDEFINED else page 1922 1923 resp = await self._request( 1924 RequestMethod.GET, 1925 f"Forum/GetTopicsPaged/{page}/{0}/{group}/{sort!s}/{date_filter}/{category_filter}/", 1926 json=body, 1927 ) 1928 assert isinstance(resp, dict) 1929 return resp 1930 1931 async def fetch_core_topics_page( 1932 self, 1933 category_filter: int, 1934 date_filter: int, 1935 sort: typing.Union[str, bytes], 1936 *, 1937 page: undefined.UndefinedOr[int] = undefined.UNDEFINED, 1938 locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.UNDEFINED, 1939 ) -> typedefs.JSONObject: 1940 body: typedefs.JSONObject = {} 1941 1942 if locales is not undefined.UNDEFINED: 1943 body["locales"] = ",".join(str(locales)) 1944 else: 1945 body["locales"] = ",".join([]) 1946 1947 resp = await self._request( 1948 RequestMethod.GET, 1949 f"Forum/GetCoreTopicsPaged/{0 if page is undefined.UNDEFINED else page}" 1950 f"/{sort!s}/{date_filter}/{category_filter}/", 1951 json=body, 1952 ) 1953 assert isinstance(resp, dict) 1954 return resp 1955 1956 async def fetch_posts_threaded_page( 1957 self, 1958 parent_post: bool, 1959 page: int, 1960 page_size: int, 1961 parent_post_id: int, 1962 reply_size: int, 1963 root_thread_mode: bool, 1964 sort_mode: int, 1965 show_banned: typing.Optional[str] = None, 1966 ) -> typedefs.JSONObject: 1967 resp = await self._request( 1968 RequestMethod.GET, 1969 f"Forum/GetPostsThreadedPaged/{parent_post}/{page}/" 1970 f"{page_size}/{reply_size}/{parent_post_id}/{root_thread_mode}/{sort_mode}/", 1971 json={"showbanned": show_banned}, 1972 ) 1973 assert isinstance(resp, dict) 1974 return resp 1975 1976 async def fetch_posts_threaded_page_from_child( 1977 self, 1978 child_id: bool, 1979 page: int, 1980 page_size: int, 1981 reply_size: int, 1982 root_thread_mode: bool, 1983 sort_mode: int, 1984 show_banned: typing.Optional[str] = None, 1985 ) -> typedefs.JSONObject: 1986 resp = await self._request( 1987 RequestMethod.GET, 1988 f"Forum/GetPostsThreadedPagedFromChild/{child_id}/" 1989 f"{page}/{page_size}/{reply_size}/{root_thread_mode}/{sort_mode}/", 1990 json={"showbanned": show_banned}, 1991 ) 1992 assert isinstance(resp, dict) 1993 return resp 1994 1995 async def fetch_post_and_parent( 1996 self, child_id: int, /, *, show_banned: typing.Optional[str] = None 1997 ) -> typedefs.JSONObject: 1998 resp = await self._request( 1999 RequestMethod.GET, 2000 f"Forum/GetPostAndParent/{child_id}/", 2001 json={"showbanned": show_banned}, 2002 ) 2003 assert isinstance(resp, dict) 2004 return resp 2005 2006 async def fetch_posts_and_parent_awaiting( 2007 self, child_id: int, /, *, show_banned: typing.Optional[str] = None 2008 ) -> typedefs.JSONObject: 2009 resp = await self._request( 2010 RequestMethod.GET, 2011 f"Forum/GetPostAndParentAwaitingApproval/{child_id}/", 2012 json={"showbanned": show_banned}, 2013 ) 2014 assert isinstance(resp, dict) 2015 return resp 2016 2017 async def fetch_topic_for_content(self, content_id: int, /) -> int: 2018 resp = await self._request( 2019 RequestMethod.GET, f"Forum/GetTopicForContent/{content_id}/" 2020 ) 2021 assert isinstance(resp, int) 2022 return resp 2023 2024 async def fetch_forum_tag_suggestions( 2025 self, partial_tag: str, / 2026 ) -> typedefs.JSONObject: 2027 resp = await self._request( 2028 RequestMethod.GET, 2029 "Forum/GetForumTagSuggestions/", 2030 json={"partialtag": partial_tag}, 2031 ) 2032 assert isinstance(resp, dict) 2033 return resp 2034 2035 async def fetch_poll(self, topic_id: int, /) -> typedefs.JSONObject: 2036 resp = await self._request(RequestMethod.GET, f"Forum/Poll/{topic_id}/") 2037 assert isinstance(resp, dict) 2038 return resp 2039 2040 async def fetch_recruitment_thread_summaries(self) -> typedefs.JSONArray: 2041 resp = await self._request(RequestMethod.POST, "Forum/Recruit/Summaries/") 2042 assert isinstance(resp, list) 2043 return resp 2044 2045 async def fetch_recommended_groups( 2046 self, 2047 accecss_token: str, 2048 /, 2049 *, 2050 date_range: int = 0, 2051 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 2052 ) -> typedefs.JSONArray: 2053 resp = await self._request( 2054 RequestMethod.POST, 2055 f"GroupV2/Recommended/{int(group_type)}/{date_range}/", 2056 auth=accecss_token, 2057 ) 2058 assert isinstance(resp, list) 2059 return resp 2060 2061 async def fetch_available_avatars(self) -> collections.Mapping[str, int]: 2062 resp = await self._request(RequestMethod.GET, "GroupV2/GetAvailableAvatars/") 2063 assert isinstance(resp, dict) 2064 return resp 2065 2066 async def fetch_user_clan_invite_setting( 2067 self, 2068 access_token: str, 2069 /, 2070 membership_type: typedefs.IntAnd[enums.MembershipType], 2071 ) -> bool: 2072 resp = await self._request( 2073 RequestMethod.GET, 2074 f"GroupV2/GetUserClanInviteSetting/{int(membership_type)}/", 2075 auth=access_token, 2076 ) 2077 assert isinstance(resp, bool) 2078 return resp 2079 2080 async def fetch_banned_group_members( 2081 self, access_token: str, group_id: int, /, *, page: int = 1 2082 ) -> typedefs.JSONObject: 2083 resp = await self._request( 2084 RequestMethod.GET, 2085 f"GroupV2/{group_id}/Banned/?currentpage={page}", 2086 auth=access_token, 2087 ) 2088 assert isinstance(resp, dict) 2089 return resp 2090 2091 async def fetch_pending_group_memberships( 2092 self, access_token: str, group_id: int, /, *, current_page: int = 1 2093 ) -> typedefs.JSONObject: 2094 resp = await self._request( 2095 RequestMethod.GET, 2096 f"GroupV2/{group_id}/Members/Pending/?currentpage={current_page}", 2097 auth=access_token, 2098 ) 2099 assert isinstance(resp, dict) 2100 return resp 2101 2102 async def fetch_invited_group_memberships( 2103 self, access_token: str, group_id: int, /, *, current_page: int = 1 2104 ) -> typedefs.JSONObject: 2105 resp = await self._request( 2106 RequestMethod.GET, 2107 f"GroupV2/{group_id}/Members/InvitedIndividuals/?currentpage={current_page}", 2108 auth=access_token, 2109 ) 2110 assert isinstance(resp, dict) 2111 return resp 2112 2113 async def invite_member_to_group( 2114 self, 2115 access_token: str, 2116 /, 2117 group_id: int, 2118 membership_id: int, 2119 membership_type: typedefs.IntAnd[enums.MembershipType], 2120 *, 2121 message: undefined.UndefinedOr[str] = undefined.UNDEFINED, 2122 ) -> typedefs.JSONObject: 2123 resp = await self._request( 2124 RequestMethod.POST, 2125 f"GroupV2/{group_id}/Members/IndividualInvite/{int(membership_type)}/{membership_id}/", 2126 auth=access_token, 2127 json={"message": str(message)}, 2128 ) 2129 assert isinstance(resp, dict) 2130 return resp 2131 2132 async def cancel_group_member_invite( 2133 self, 2134 access_token: str, 2135 /, 2136 group_id: int, 2137 membership_id: int, 2138 membership_type: typedefs.IntAnd[enums.MembershipType], 2139 ) -> typedefs.JSONObject: 2140 resp = await self._request( 2141 RequestMethod.POST, 2142 f"GroupV2/{group_id}/Members/IndividualInviteCancel/{int(membership_type)}/{membership_id}/", 2143 auth=access_token, 2144 ) 2145 assert isinstance(resp, dict) 2146 return resp 2147 2148 async def fetch_historical_definition(self) -> typedefs.JSONObject: 2149 resp = await self._request(RequestMethod.GET, "Destiny2/Stats/Definition/") 2150 assert isinstance(resp, dict) 2151 return resp 2152 2153 async def fetch_historical_stats( 2154 self, 2155 character_id: int, 2156 membership_id: int, 2157 membership_type: typedefs.IntAnd[enums.MembershipType], 2158 day_start: datetime.datetime, 2159 day_end: datetime.datetime, 2160 groups: list[typedefs.IntAnd[enums.StatsGroupType]], 2161 modes: collections.Sequence[typedefs.IntAnd[enums.GameMode]], 2162 *, 2163 period_type: enums.PeriodType = enums.PeriodType.ALL_TIME, 2164 ) -> typedefs.JSONObject: 2165 end, start = time.parse_date_range(day_end, day_start) 2166 resp = await self._request( 2167 RequestMethod.GET, 2168 f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/", 2169 json={ 2170 "dayend": end, 2171 "daystart": start, 2172 "groups": [str(int(group)) for group in groups], 2173 "modes": [str(int(mode)) for mode in modes], 2174 "periodType": int(period_type), 2175 }, 2176 ) 2177 assert isinstance(resp, dict) 2178 return resp 2179 2180 async def fetch_historical_stats_for_account( 2181 self, 2182 membership_id: int, 2183 membership_type: typedefs.IntAnd[enums.MembershipType], 2184 groups: list[typedefs.IntAnd[enums.StatsGroupType]], 2185 ) -> typedefs.JSONObject: 2186 resp = await self._request( 2187 RequestMethod.GET, 2188 f"Destiny2/{int(membership_type)}/Account/{membership_id}/Stats/", 2189 json={"groups": [str(int(group)) for group in groups]}, 2190 ) 2191 assert isinstance(resp, dict) 2192 return resp 2193 2194 async def fetch_aggregated_activity_stats( 2195 self, 2196 character_id: int, 2197 membership_id: int, 2198 membership_type: typedefs.IntAnd[enums.MembershipType], 2199 /, 2200 ) -> typedefs.JSONObject: 2201 resp = await self._request( 2202 RequestMethod.GET, 2203 f"Destiny2/{int(membership_type)}/Account/{membership_id}/" 2204 f"Character/{character_id}/Stats/AggregateActivityStats/", 2205 ) 2206 assert isinstance(resp, dict) 2207 return resp 2208 2209 async def equip_loadout( 2210 self, 2211 access_token: str, 2212 /, 2213 loadout_index: int, 2214 character_id: int, 2215 membership_type: typedefs.IntAnd[enums.MembershipType], 2216 ) -> None: 2217 response = await self._request( 2218 RequestMethod.POST, 2219 "Destiny2/Actions/Loadouts/EquipLoadout/", 2220 json={ 2221 "loadoutIndex": loadout_index, 2222 "characterId": character_id, 2223 "membership_type": int(membership_type), 2224 }, 2225 auth=access_token, 2226 ) 2227 assert isinstance(response, int) 2228 2229 async def snapshot_loadout( 2230 self, 2231 access_token: str, 2232 /, 2233 loadout_index: int, 2234 character_id: int, 2235 membership_type: typedefs.IntAnd[enums.MembershipType], 2236 *, 2237 color_hash: typing.Optional[int] = None, 2238 icon_hash: typing.Optional[int] = None, 2239 name_hash: typing.Optional[int] = None, 2240 ) -> None: 2241 response = await self._request( 2242 RequestMethod.POST, 2243 "Destiny2/Actions/Loadouts/SnapshotLoadout/", 2244 auth=access_token, 2245 json={ 2246 "colorHash": color_hash, 2247 "iconHash": icon_hash, 2248 "nameHash": name_hash, 2249 "loadoutIndex": loadout_index, 2250 "characterId": character_id, 2251 "membershipType": int(membership_type), 2252 }, 2253 ) 2254 assert isinstance(response, int) 2255 2256 async def update_loadout( 2257 self, 2258 access_token: str, 2259 /, 2260 loadout_index: int, 2261 character_id: int, 2262 membership_type: typedefs.IntAnd[enums.MembershipType], 2263 *, 2264 color_hash: typing.Optional[int] = None, 2265 icon_hash: typing.Optional[int] = None, 2266 name_hash: typing.Optional[int] = None, 2267 ) -> None: 2268 response = await self._request( 2269 RequestMethod.POST, 2270 "Destiny2/Actions/Loadouts/UpdateLoadoutIdentifiers/", 2271 auth=access_token, 2272 json={ 2273 "colorHash": color_hash, 2274 "iconHash": icon_hash, 2275 "nameHash": name_hash, 2276 "loadoutIndex": loadout_index, 2277 "characterId": character_id, 2278 "membershipType": int(membership_type), 2279 }, 2280 ) 2281 assert isinstance(response, int) 2282 2283 async def clear_loadout( 2284 self, 2285 access_token: str, 2286 /, 2287 loadout_index: int, 2288 character_id: int, 2289 membership_type: typedefs.IntAnd[enums.MembershipType], 2290 ) -> None: 2291 response = await self._request( 2292 RequestMethod.POST, 2293 "Destiny2/Actions/Loadouts/ClearLoadout/", 2294 json={ 2295 "loadoutIndex": loadout_index, 2296 "characterId": character_id, 2297 "membership_type": int(membership_type), 2298 }, 2299 auth=access_token, 2300 ) 2301 assert isinstance(response, int)
A RESTful client implementation for Bungie's API.
This client is designed to only make HTTP requests and return JSON objects to provide RESTful functionality.
This client is the core for aiobungie.Client which deserialize those returned JSON objects
using the factory into Pythonic data classes objects which provide Python functionality.
Example
import aiobungie
client = aiobungie.RESTClient("TOKEN")
async with client:
response = await client.fetch_clan_members(4389205)
for member in response['results']:
for key, value in member['destinyUserInfo'].items():
print(key, value)
Parameters
- token (
str): A valid application token from Bungie's developer portal.
Other Parameters
- max_retries (
int): The max retries number to retry if the request hit a5xxstatus code. - client_secret (
typing.Optional[str]): An optional application client secret, This is only needed if you're fetching OAuth2 tokens with this client. - client_id (
typing.Optional[int]): An optional application client id, This is only needed if you're fetching OAuth2 tokens with this client. - enable_debugging (
bool | str): Whether to enable logging responses or not.
Logging Levels
False: This will disable logging.True: This will set the level toDEBUGand enable logging minimal information."TRACE" | TRACE: This will log the response headers along with the minimal information.
368 def __init__( 369 self, 370 token: str, 371 /, 372 *, 373 client_secret: typing.Optional[str] = None, 374 client_id: typing.Optional[int] = None, 375 client_session: typing.Optional[aiohttp.ClientSession] = None, 376 dumps: typedefs.Dumps = helpers.dumps, 377 loads: typedefs.Loads = helpers.loads, 378 max_retries: int = 4, 379 enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False, 380 ) -> None: 381 self._session: typing.Optional[aiohttp.ClientSession] = client_session 382 self._lock: typing.Optional[asyncio.Lock] = None 383 self._client_secret = client_secret 384 self._client_id = client_id 385 self._token: str = token 386 self._max_retries = max_retries 387 self._dumps = dumps 388 self._loads = loads 389 self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {} 390 391 self._set_debug_level(enable_debugging)
A mutable mapping storage for the user's needs.
This mapping is useful for storing any kind of data that the user may need.
Example
import aiobungie
client = aiobungie.RESTClient(…)
async with client:
# Fetch auth tokens and store them
client.metadata["tokens"] = await client.fetch_access_token("code")
# Some other time.
async with client:
# Retrieve the tokens
tokens: aiobungie.OAuth2Response = client.metadata["tokens"]
# Use them to fetch your user.
user = await client.fetch_current_user_memberships(tokens.access_token)
405 @typing.final 406 async def close(self) -> None: 407 if self._session is None: 408 raise RuntimeError("REST client is not running.") 409 410 await self._session.close() 411 self._session = None
Close this REST client session if it was acquired.
This method is automatically called when using async with contextmanager.
Raises
RuntimeError: If the client is already closed.
413 @typing.final 414 def open(self) -> None: 415 """Open a new client session. This is called internally with contextmanager usage.""" 416 if self._session: 417 raise RuntimeError("Cannot open REST client when it's already open.") 418 419 self._session = aiohttp.ClientSession( 420 connector=aiohttp.TCPConnector(), 421 connector_owner=True, 422 raise_for_status=False, 423 timeout=aiohttp.ClientTimeout(total=30.0), 424 )
Open a new client session. This is called internally with contextmanager usage.
426 @typing.final 427 def enable_debugging( 428 self, 429 level: typing.Union[typing.Literal["TRACE"], bool, int] = False, 430 file: typing.Optional[typing.Union[pathlib.Path, str]] = None, 431 /, 432 ) -> None: 433 self._set_debug_level(level, file)
Enables debugging for the REST calls.
Logging Levels
False: This will disable logging.True: This will set the level toDEBUGand enable logging minimal information."TRACE"|TRACE: This will log the response headers along with the minimal information.
Parameters
- level (
str | bool | int): The level of debugging to enable. - file (
pathlib.Path | str | None): The file path to write the debug logs to. If provided.
435 @typing.final 436 async def static_request( 437 self, 438 method: typing.Union[RequestMethod, str], 439 path: str, 440 *, 441 auth: typing.Optional[str] = None, 442 json: typing.Optional[dict[str, typing.Any]] = None, 443 ) -> ResponseSig: 444 return await self._request(method, path, auth=auth, json=json)
Perform an HTTP request given a valid Bungie endpoint.
Parameters
- method (
RequestMethod | str): The request method, This may beGET,POST,PUT, etc. - path (
str): The Bungie endpoint or path. A path must look something like thisDestiny2/3/Profile/46111239123/... - auth (
str | None): An optional bearer token for methods that requires OAuth2 Authorization header. - json (
dict[str, typing.Any] | None): An optional JSON data to include in the request.
Returns
aiobungie.rest.ResponseSig: The response payload.
446 @typing.final 447 def build_oauth2_url( 448 self, client_id: typing.Optional[int] = None 449 ) -> typing.Optional[builders.OAuthURL]: 450 client_id = client_id or self._client_id 451 if client_id is None: 452 return None 453 454 return builders.OAuthURL(client_id=client_id)
Builds an OAuth2 URL using the provided user REST/Base client secret/id.
You can't get the complete string URL by using .compile() method.
Parameters
- client_id (
int | None): An optional client id to provide, If leftNoneit will roll back to the id passed to theRESTClient, If both isNonethis method will returnNone.
Returns
aiobungie.builders.OAuthURL | None: If the client id was provided as a parameter or provided inaiobungie.RESTClient, A complete OAuthURL object will be returned. OtherwiseNonewill be returned.
656 async def fetch_oauth2_tokens(self, code: str, /) -> builders.OAuth2Response: 657 if not isinstance(self._client_secret, (str, int)): 658 raise TypeError( 659 "Expected (str, int) for client secret " 660 f"but got {type(self._client_secret).__name__}" # type: ignore 661 ) 662 663 headers = { 664 "client_secret": self._client_secret, 665 } 666 667 data = ( 668 f"grant_type=authorization_code&code={code}" 669 f"&client_id={self._client_id}&client_secret={self._client_secret}" 670 ) 671 672 response = await self._request( 673 RequestMethod.POST, "", headers=headers, json=data, oauth2=True 674 ) 675 assert isinstance(response, dict) 676 return builders.OAuth2Response.build_response(response)
Makes a POST request and fetch the OAuth2 access_token and refresh token.
Parameters
- code (
str): The Authorization code received from the authorization endpoint found in the URL parameters.
Returns
aiobungie.builders.OAuth2Response: An OAuth2 deserialized response.
Raises
Unauthorized: The passed code was invalid.
678 async def refresh_access_token( 679 self, refresh_token: str, / 680 ) -> builders.OAuth2Response: 681 if not isinstance(self._client_secret, (int, str)): 682 raise TypeError( 683 f"Expected (str, int) for client secret but got {type(self._client_secret).__name__}" # type: ignore 684 ) 685 686 data = { 687 "grant_type": "refresh_token", 688 "refresh_token": refresh_token, 689 "client_id": self._client_id, 690 "client_secret": self._client_secret, 691 "Content-Type": "application/x-www-form-urlencoded", 692 } 693 694 response = await self._request(RequestMethod.POST, "", json=data, oauth2=True) 695 assert isinstance(response, dict) 696 return builders.OAuth2Response.build_response(response)
Refresh OAuth2 access token given its refresh token.
Parameters
- refresh_token (
str): The refresh token.
Returns
aiobungie.builders.OAuth2Response: An OAuth2 deserialized response.
698 async def fetch_bungie_user(self, id: int) -> typedefs.JSONObject: 699 resp = await self._request( 700 RequestMethod.GET, f"User/GetBungieNetUserById/{id}/" 701 ) 702 assert isinstance(resp, dict) 703 return resp
Fetch a Bungie user by their id.
Parameters
- id (
int): The user id.
Returns
aiobungie.typedefs.JSONObject: A JSON object of users objects.
Raises
NotFound: The user was not found.
710 async def fetch_membership_from_id( 711 self, 712 id: int, 713 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 714 /, 715 ) -> typedefs.JSONObject: 716 resp = await self._request( 717 RequestMethod.GET, f"User/GetMembershipsById/{id}/{int(type)}" 718 ) 719 assert isinstance(resp, dict) 720 return resp
Fetch Bungie user's memberships from their id.
Parameters
- id (
int): The user's id. - type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The user's membership type.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the found user.
Raises
- aiobungie.NotFound: The requested user was not found.
722 async def fetch_player( 723 self, 724 name: str, 725 code: int, 726 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL, 727 /, 728 ) -> typedefs.JSONArray: 729 resp = await self._request( 730 RequestMethod.POST, 731 f"Destiny2/SearchDestinyPlayerByBungieName/{int(type)}", 732 json={"displayName": name, "displayNameCode": code}, 733 ) 734 assert isinstance(resp, list) 735 return resp
Fetch a Destiny 2 Player.
Parameters
- name (
str): The unique Bungie player name. - code (
int): The unique Bungie display name code. - type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The player's membership type, e,g. XBOX, STEAM, PSN
Returns
aiobungie.typedefs.JSONArray: A JSON array of the found player's memberships.
Raises
aiobungie.NotFound: The player was not found.aiobungie.MembershipTypeError: The provided membership type was invalid.
737 async def search_users(self, name: str, /) -> typedefs.JSONObject: 738 resp = await self._request( 739 RequestMethod.POST, 740 "User/Search/GlobalName/0", 741 json={"displayNamePrefix": name}, 742 ) 743 assert isinstance(resp, dict) 744 return resp
Search for users by their global name and return all users who share this name.
Parameters
- name (
str): The user name.
Returns
aiobungie.typedefs.JSONObject: A JSON object of an array of the found users.
Raises
aiobungie.NotFound: The user(s) was not found.
746 async def fetch_clan_from_id( 747 self, id: int, /, access_token: typing.Optional[str] = None 748 ) -> typedefs.JSONObject: 749 resp = await self._request( 750 RequestMethod.GET, f"GroupV2/{id}", auth=access_token 751 ) 752 assert isinstance(resp, dict) 753 return resp
Fetch a Bungie Clan by its id.
Parameters
- id (
int): The clan id.
Other Parameters
access_token (
typing.Optional[str]): An optional access token to make the request with.If the token was bound to a member of the clan, This field
aiobungie.crates.Clan.current_user_membershipwill be available and will return the membership of the user who made this request.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the clan.
Raises
aiobungie.NotFound: The clan was not found.
755 async def fetch_clan( 756 self, 757 name: str, 758 /, 759 access_token: typing.Optional[str] = None, 760 *, 761 type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 762 ) -> typedefs.JSONObject: 763 resp = await self._request( 764 RequestMethod.GET, f"GroupV2/Name/{name}/{int(type)}", auth=access_token 765 ) 766 assert isinstance(resp, dict) 767 return resp
Fetch a Clan by its name. This method will return the first clan found with given name name.
Parameters
- name (
str): The clan name.
Other Parameters
access_token (
typing.Optional[str]): An optional access token to make the request with.If the token was bound to a member of the clan, This field
aiobungie.crates.Clan.current_user_membershipwill be available and will return the membership of the user who made this request.- type (
aiobungie.typedefs.IntAnd[aiobungie.GroupType]): The group type, Default is one.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the clan.
Raises
aiobungie.NotFound: The clan was not found.
769 async def fetch_clan_admins(self, clan_id: int, /) -> typedefs.JSONObject: 770 resp = await self._request( 771 RequestMethod.GET, f"GroupV2/{clan_id}/AdminsAndFounder/" 772 ) 773 assert isinstance(resp, dict) 774 return resp
Fetch the admins and founder members of the clan.
Parameters
- clan_id (
int): The clan id.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the clan admins and founder members.
Raises
aiobungie.NotFound: The clan was not found.
776 async def fetch_clan_conversations(self, clan_id: int, /) -> typedefs.JSONArray: 777 resp = await self._request( 778 RequestMethod.GET, f"GroupV2/{clan_id}/OptionalConversations/" 779 ) 780 assert isinstance(resp, list) 781 return resp
Fetch a clan's conversations.
Parameters
- clan_id (
int): The clan's id.
Returns
aiobungie.typedefs.JSONArray: A JSON array of the conversations.
783 async def fetch_application(self, appid: int, /) -> typedefs.JSONObject: 784 resp = await self._request(RequestMethod.GET, f"App/Application/{appid}") 785 assert isinstance(resp, dict) 786 return resp
Fetch a Bungie Application.
Parameters
- appid (
int): The application id.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the application.
788 async def fetch_character( 789 self, 790 member_id: int, 791 membership_type: typedefs.IntAnd[enums.MembershipType], 792 character_id: int, 793 components: list[enums.ComponentType], 794 auth: typing.Optional[str] = None, 795 ) -> typedefs.JSONObject: 796 collector = _collect_components(components) 797 response = await self._request( 798 RequestMethod.GET, 799 f"Destiny2/{int(membership_type)}/Profile/{member_id}/" 800 f"Character/{character_id}/?components={collector}", 801 auth=auth, 802 ) 803 assert isinstance(response, dict) 804 return response
Fetch a Destiny 2 player's characters.
Parameters
- member_id (
int): A valid bungie member id. - membership_type (
aiobungie.typedefs.IntAnd[MembershipType]): The member's membership type. - character_id (
int): The character id to return. - components (
list[aiobungie.ComponentType]): A list of character components to collect and return.
Other Parameters
- auth (
typing.Optional[str]): A bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the requested character.
Raises
aiobungie.MembershipTypeError: The provided membership type was invalid.
806 async def fetch_activities( 807 self, 808 member_id: int, 809 character_id: int, 810 mode: typedefs.IntAnd[enums.GameMode], 811 membership_type: typedefs.IntAnd[ 812 enums.MembershipType 813 ] = enums.MembershipType.ALL, 814 *, 815 page: int = 0, 816 limit: int = 1, 817 ) -> typedefs.JSONObject: 818 resp = await self._request( 819 RequestMethod.GET, 820 f"Destiny2/{int(membership_type)}/Account/" 821 f"{member_id}/Character/{character_id}/Stats/Activities" 822 f"/?mode={int(mode)}&count={limit}&page={page}", 823 ) 824 assert isinstance(resp, dict) 825 return resp
Fetch a Destiny 2 activity for the specified user id and character.
Parameters
- member_id (
int): The user id that starts with4611. - character_id (
int): The id of the character to retrieve. - mode (
aiobungie.typedefs.IntAnd[aiobungie.GameMode]): This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc.
Other Parameters
- membership_type (
aiobungie.typedefs.IntAnd[MembershipType]): The Member ship type, if nothing was passed than it will return all. - page (
int): The page number. Default to1 - limit (
int): Limit the returned result. Default to1
Returns
aiobungie.typedefs.JSONObject: A JSON object of the player's activities.
Raises
NotFound: The activity was not found.aiobungie.MembershipTypeError: The provided membership type was invalid.
835 async def fetch_profile( 836 self, 837 membership_id: int, 838 type: typedefs.IntAnd[enums.MembershipType], 839 components: list[enums.ComponentType], 840 auth: typing.Optional[str] = None, 841 ) -> typedefs.JSONObject: 842 collector = _collect_components(components) 843 response = await self._request( 844 RequestMethod.GET, 845 f"Destiny2/{int(type)}/Profile/{membership_id}/?components={collector}", 846 auth=auth, 847 ) 848 assert isinstance(response, dict) 849 return response
Fetch a bungie profile.
Parameters
- membership_id (
int): The member's id. - type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): A valid membership type. - components (
list[aiobungie.ComponentType]): A list of profile components to collect and return.
Other Parameters
- auth (
typing.Optional[str]): A bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the found profile.
Raises
aiobungie.MembershipTypeError: The provided membership type was invalid.
851 async def fetch_entity(self, type: str, hash: int) -> typedefs.JSONObject: 852 response = await self._request( 853 RequestMethod.GET, route=f"Destiny2/Manifest/{type}/{hash}" 854 ) 855 assert isinstance(response, dict) 856 return response
Fetch a Destiny definition item given its type and hash.
Parameters
- type (
str): Entity's type definition. - hash (
int): Entity's hash.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the definition data.
858 async def fetch_inventory_item(self, hash: int, /) -> typedefs.JSONObject: 859 resp = await self.fetch_entity("DestinyInventoryItemDefinition", hash) 860 assert isinstance(resp, dict) 861 return resp
Fetch a Destiny inventory item entity given a its hash.
Parameters
- hash (
int): Entity's hash.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the inventory item.
863 async def fetch_objective_entity(self, hash: int, /) -> typedefs.JSONObject: 864 resp = await self.fetch_entity("DestinyObjectiveDefinition", hash) 865 assert isinstance(resp, dict) 866 return resp
Fetch a Destiny objective entity given a its hash.
Parameters
- hash (
int): objective's hash.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the objective data.
868 async def fetch_groups_for_member( 869 self, 870 member_id: int, 871 member_type: typedefs.IntAnd[enums.MembershipType], 872 /, 873 *, 874 filter: int = 0, 875 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 876 ) -> typedefs.JSONObject: 877 resp = await self._request( 878 RequestMethod.GET, 879 f"GroupV2/User/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/", 880 ) 881 assert isinstance(resp, dict) 882 return resp
Fetch the information about the groups for a member.
Parameters
- member_id (
int): The member's id - member_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Other Parameters
- filter (
int): Filter apply to list of joined groups. This Default to0 - group_type (
aiobungie.typedefs.IntAnd[aiobungie.GroupType]): The group's type. This is always set toaiobungie.GroupType.CLANand should not be changed.
Returns
aiobungie.typedefs.JSONObject: A JSON object of an array of the member's membership data and groups data.
884 async def fetch_potential_groups_for_member( 885 self, 886 member_id: int, 887 member_type: typedefs.IntAnd[enums.MembershipType], 888 /, 889 *, 890 filter: int = 0, 891 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 892 ) -> typedefs.JSONObject: 893 resp = await self._request( 894 RequestMethod.GET, 895 f"GroupV2/User/Potential/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/", 896 ) 897 assert isinstance(resp, dict) 898 return resp
Get information about the groups that a given member has applied to or been invited to.
Parameters
- member_id (
int): The member's id - member_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Other Parameters
- filter (
int): Filter apply to list of joined groups. This Default to0 - group_type (
aiobungie.typedefs.IntAnd[aiobungie.GroupType]): The group's type. This is always set toaiobungie.GroupType.CLANand should not be changed.
Returns
aiobungie.typedefs.JSONObject: A JSON object of an array of the member's membership data and groups data.
900 async def fetch_clan_members( 901 self, 902 clan_id: int, 903 /, 904 *, 905 name: typing.Optional[str] = None, 906 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 907 ) -> typedefs.JSONObject: 908 resp = await self._request( 909 RequestMethod.GET, 910 f"/GroupV2/{clan_id}/Members/?memberType={int(type)}&nameSearch={name if name else ''}¤tpage=1", 911 ) 912 assert isinstance(resp, dict) 913 return resp
Fetch all Bungie Clan members.
Parameters
- clan_id (
int): The clans id
Other Parameters
- name (
typing.Optional[str]): If provided, Only players matching this name will be returned. - type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): An optional clan member's membership type. Default is set toaiobungie.MembershipType.NONEWhich returns the first matched clan member by their name.
Returns
aiobungie.typedefs.JSONObject: A JSON object of an array of clan members.
Raises
aiobungie.NotFound: The clan was not found.
915 async def fetch_hardlinked_credentials( 916 self, 917 credential: int, 918 type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID, 919 /, 920 ) -> typedefs.JSONObject: 921 resp = await self._request( 922 RequestMethod.GET, 923 f"User/GetMembershipFromHardLinkedCredential/{int(type)}/{credential}/", 924 ) 925 assert isinstance(resp, dict) 926 return resp
Gets any hard linked membership given a credential.
Only works for credentials that are public just aiobungie.CredentialType.STEAMID right now.
Cross Save aware.
Parameters
- credential (
int): A valid SteamID64 - type (
aiobungie.typedefs.IntAnd[aiobungie.CredentialType]): The credential type. This must not be changed Since its only credential that works "currently"
Returns
aiobungie.typedefs.JSONObject: A JSON object of the found user hard linked types.
928 async def fetch_user_credentials( 929 self, access_token: str, membership_id: int, / 930 ) -> typedefs.JSONArray: 931 resp = await self._request( 932 RequestMethod.GET, 933 f"User/GetCredentialTypesForTargetAccount/{membership_id}", 934 auth=access_token, 935 ) 936 assert isinstance(resp, list) 937 return resp
Fetch an array of credential types attached to the requested account.
This method require OAuth2 Bearer access token.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - membership_id (
int): The id of the membership to return.
Returns
aiobungie.typedefs.JSONArray: A JSON array of the returned credentials.
Raises
aiobungie.Unauthorized: The access token was wrong or no access token passed.
939 async def insert_socket_plug( 940 self, 941 action_token: str, 942 /, 943 instance_id: int, 944 plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]], 945 character_id: int, 946 membership_type: typedefs.IntAnd[enums.MembershipType], 947 ) -> typedefs.JSONObject: 948 if isinstance(plug, builders.PlugSocketBuilder): 949 plug = plug.collect() 950 951 body = { 952 "actionToken": action_token, 953 "itemInstanceId": instance_id, 954 "plug": plug, 955 "characterId": character_id, 956 "membershipType": int(membership_type), 957 } 958 resp = await self._request( 959 RequestMethod.POST, "Destiny2/Actions/Items/InsertSocketPlug", json=body 960 ) 961 assert isinstance(resp, dict) 962 return resp
Insert a plug into a socketed item.
OAuth2: AdvancedWriteActions scope is required
Parameters
- action_token (
str): Action token provided by the AwaGetActionToken API call. - instance_id (
int): The item instance id that's plug inserted. - plug (
typing.Union[aiobungie.builders.PlugSocketBuilder, dict[str, int]]): Either a PlugSocketBuilder object or a raw dict contains key, value for the plug entries.
Example
plug = (
aiobungie.PlugSocketBuilder()
.set_socket_array(0)
.set_socket_index(0)
.set_plug_item(3023847)
.collect()
)
await insert_socket_plug_free(..., plug=plug)
character_id : int
The character's id.
membership_type : aiobungie.typedefs.IntAnd[aiobungie.MembershipType]
The membership type.
Returns
aiobungie.typedefs.JSONObject: A JSON object contains the changed item details.
Raises
aiobungie.Unauthorized: The access token was wrong or no access token passed.
964 async def insert_socket_plug_free( 965 self, 966 access_token: str, 967 /, 968 instance_id: int, 969 plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]], 970 character_id: int, 971 membership_type: typedefs.IntAnd[enums.MembershipType], 972 ) -> typedefs.JSONObject: 973 if isinstance(plug, builders.PlugSocketBuilder): 974 plug = plug.collect() 975 976 body = { 977 "itemInstanceId": instance_id, 978 "plug": plug, 979 "characterId": character_id, 980 "membershipType": int(membership_type), 981 } 982 resp = await self._request( 983 RequestMethod.POST, 984 "Destiny2/Actions/Items/InsertSocketPlugFree", 985 json=body, 986 auth=access_token, 987 ) 988 assert isinstance(resp, dict) 989 return resp
Insert a plug into a socketed item. This doesn't require an Action token.
OAuth2: MoveEquipDestinyItems scope is required
Parameters
- instance_id (
int): The item instance id that's plug inserted. - plug (
typing.Union[aiobungie.builders.PlugSocketBuilder, dict[str, int]]): Either a PlugSocketBuilder object or a raw dict contains key, value for the plug entries.
Example
plug = (
aiobungie.PlugSocketBuilder()
.set_socket_array(0)
.set_socket_index(0)
.set_plug_item(3023847)
.collect()
)
await insert_socket_plug_free(..., plug=plug)
character_id : int
The character's id.
membership_type : aiobungie.typedefs.IntAnd[aiobungie.MembershipType]
The membership type.
Returns
aiobungie.typedefs.JSONObject: A JSON object contains the changed item details.
Raises
aiobungie.Unauthorized: The access token was wrong or no access token passed.
991 async def set_item_lock_state( 992 self, 993 access_token: str, 994 state: bool, 995 /, 996 item_id: int, 997 character_id: int, 998 membership_type: typedefs.IntAnd[enums.MembershipType], 999 ) -> int: 1000 body = { 1001 "state": state, 1002 "itemId": item_id, 1003 "characterId": character_id, 1004 "membershipType": int(membership_type), 1005 } 1006 response = await self._request( 1007 RequestMethod.POST, 1008 "Destiny2/Actions/Items/SetLockState", 1009 json=body, 1010 auth=access_token, 1011 ) 1012 assert isinstance(response, int) 1013 return response
Set the Lock State for an instanced item.
OAuth2: MoveEquipDestinyItems scope is required
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - state (
bool): IfTrue, The item will be locked, IfFalse, The item will be unlocked. - item_id (
int): The item id. - character_id (
int): The character id. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type for the associated account.
Returns
int: An integer represents whether the request was successful or failed.
Raises
aiobungie.Unauthorized: - The access token was wrong- No access token passed.
- Other authorization causes.
1015 async def set_quest_track_state( 1016 self, 1017 access_token: str, 1018 state: bool, 1019 /, 1020 item_id: int, 1021 character_id: int, 1022 membership_type: typedefs.IntAnd[enums.MembershipType], 1023 ) -> int: 1024 body = { 1025 "state": state, 1026 "itemId": item_id, 1027 "characterId": character_id, 1028 "membership_type": int(membership_type), 1029 } 1030 response = await self._request( 1031 RequestMethod.POST, 1032 "Destiny2/Actions/Items/SetTrackedState", 1033 json=body, 1034 auth=access_token, 1035 ) 1036 assert isinstance(response, int) 1037 return response
Set the Tracking State for an instanced Quest or Bounty.
OAuth2: MoveEquipDestinyItems scope is required
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - state (
bool): IfTrue, The item will be locked, IfFalse, The item will be unlocked. - item_id (
int): The item id. - character_id (
int): The character id. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type for the associated account.
Returns
int: An integer represents whether the request was successful or failed.
Raises
aiobungie.Unauthorized: - The access token was wrong- No access token passed.
- Other authorization causes.
1039 async def fetch_manifest_path(self) -> typedefs.JSONObject: 1040 path = await self._request(RequestMethod.GET, "Destiny2/Manifest") 1041 assert isinstance(path, dict) 1042 return path
Fetch the manifest JSON paths.
Returns
typedefs.JSONObject: The manifest JSON paths.
1044 async def read_manifest_bytes(self, language: str = "en", /) -> bytes: 1045 _ensure_manifest_language(language) 1046 1047 content = await self.fetch_manifest_path() 1048 resp = await self._request( 1049 RequestMethod.GET, 1050 content["mobileWorldContentPaths"][language], 1051 unwrapping="read", 1052 base=True, 1053 ) 1054 assert isinstance(resp, bytes) 1055 return resp
Read raw manifest SQLite database bytes response.
This method can be used to write the bytes to zipped file and then extract it to get the manifest content.
Parameters
- language (
str): The manifest database language bytes to get.
Returns
bytes: The bytes to read and write the manifest database.
1057 async def download_manifest( 1058 self, 1059 language: str = "en", 1060 name: str = "manifest", 1061 path: typing.Union[pathlib.Path, str] = ".", 1062 *, 1063 force: bool = False, 1064 ) -> None: 1065 complete_path = _get_path(name, path, sql=True) 1066 1067 if complete_path.exists() and force: 1068 if force: 1069 _LOG.info( 1070 f"Found manifest in {complete_path!s}. Forcing to Re-Download." 1071 ) 1072 complete_path.unlink(missing_ok=True) 1073 1074 return await self.download_manifest(language, name, path, force=force) 1075 1076 else: 1077 raise FileExistsError( 1078 "Manifest file already exists, " 1079 "To force download, set the `force` parameter to `True`." 1080 ) 1081 1082 _LOG.info(f"Downloading manifest. Location: {complete_path!s}") 1083 data_bytes = await self.read_manifest_bytes(language) 1084 await asyncio.get_running_loop().run_in_executor( 1085 None, _write_sqlite_bytes, data_bytes, path, name 1086 )
A helper method to download the manifest.
Note
This method downloads the sqlite database and not JSON.
Use RESTInterface.download_json_manifest for the JSON version.
Parameters
- language (
str): The manifest language to download, Default is english. - path (
str|pathlib.Path): The path to save the manifest sqlite database. Example"D:/", Default is the current directory. - name (
str): The manifest database file name. Default ismanifest - force (
bool): Whether to force the download. Default isFalse. However if set to true the old file will get removed and a new one will being to download.
Returns
None
Raises
FileNotFoundError: If the manifest file exists andforceisFalse.ValueError: If the provided language was not recognized.
1088 async def download_json_manifest( 1089 self, 1090 file_name: str = "manifest", 1091 path: typing.Union[str, pathlib.Path] = ".", 1092 language: str = "en", 1093 ) -> None: 1094 _ensure_manifest_language(language) 1095 1096 _LOG.info(f"Downloading manifest JSON to {_get_path(file_name, path)!r}...") 1097 1098 content = await self.fetch_manifest_path() 1099 json_bytes = await self._request( 1100 RequestMethod.GET, 1101 content["jsonWorldContentPaths"][language], 1102 unwrapping="read", 1103 base=True, 1104 ) 1105 1106 await asyncio.get_running_loop().run_in_executor( 1107 None, _write_json_bytes, json_bytes, file_name, path 1108 ) 1109 _LOG.info("Finished downloading manifest JSON.")
Download the Bungie manifest json file.
Parameters
- file_name (
str): The file name to save the manifest json file. Default ismanifest. - path (
str|pathlib.Path): The path to save the manifest json file. Default is the current directory. Example"D:/" - language (
str): The manifest database language bytes to get. Default is English.
1111 async def fetch_manifest_version(self) -> str: 1112 return typing.cast(str, (await self.fetch_manifest_path())["version"])
Fetch the manifest version.
Returns
str: The manifest version.
1114 async def fetch_linked_profiles( 1115 self, 1116 member_id: int, 1117 member_type: typedefs.IntAnd[enums.MembershipType], 1118 /, 1119 *, 1120 all: bool = False, 1121 ) -> typedefs.JSONObject: 1122 resp = await self._request( 1123 RequestMethod.GET, 1124 f"Destiny2/{int(member_type)}/Profile/{member_id}/LinkedProfiles/?getAllMemberships={all}", 1125 ) 1126 assert isinstance(resp, dict) 1127 return resp
Returns a summary information about all profiles linked to the requested member.
The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships.
It will only return linked accounts whose linkages you are allowed to view.
Parameters
- member_id (
int): The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID. - member_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The type for the membership whose linked Destiny account you want to return.
Other Parameters
all (
bool): If provided and set toTrue, All memberships regardless of whether they're obscured by overrides will be returned,If provided and set to
False, Only available memberships will be returned. The default for this isFalse.
Returns
aiobungie.typedefs.JSONObject- A JSON object which contains an Array of profiles, an Array of profiles with errors and Bungie.Net membership
1136 async def fetch_public_milestones(self) -> typedefs.JSONObject: 1137 resp = await self._request(RequestMethod.GET, "Destiny2/Milestones/") 1138 assert isinstance(resp, dict) 1139 return resp
Fetch the available milestones.
Returns
aiobungie.typedefs.JSONObject: A JSON object of information about the milestones.
1141 async def fetch_public_milestone_content( 1142 self, milestone_hash: int, / 1143 ) -> typedefs.JSONObject: 1144 resp = await self._request( 1145 RequestMethod.GET, f"Destiny2/Milestones/{milestone_hash}/Content/" 1146 ) 1147 assert isinstance(resp, dict) 1148 return resp
Fetch the milestone content given its hash.
Parameters
- milestone_hash (
int): The milestone hash.
Returns
aiobungie.typedefs.JSONObject: A JSON object of information related to the fetched milestone.
1150 async def fetch_current_user_memberships( 1151 self, access_token: str, / 1152 ) -> typedefs.JSONObject: 1153 resp = await self._request( 1154 RequestMethod.GET, 1155 "User/GetMembershipsForCurrentUser/", 1156 auth=access_token, 1157 ) 1158 assert isinstance(resp, dict) 1159 return resp
Fetch a bungie user's accounts with the signed in user. This GET method requires a Bearer access token for the authorization.
This requires OAuth2 scope enabled and the valid Bearer access_token.
Parameters
- access_token (
str): The bearer access token associated with the bungie account.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the bungie net user and destiny memberships of this account.
1161 async def equip_item( 1162 self, 1163 access_token: str, 1164 /, 1165 item_id: int, 1166 character_id: int, 1167 membership_type: typedefs.IntAnd[enums.MembershipType], 1168 ) -> None: 1169 payload = { 1170 "itemId": item_id, 1171 "characterId": character_id, 1172 "membershipType": int(membership_type), 1173 } 1174 1175 await self._request( 1176 RequestMethod.POST, 1177 "Destiny2/Actions/Items/EquipItem/", 1178 json=payload, 1179 auth=access_token, 1180 )
Equip an item to a character.
This requires the OAuth2: MoveEquipDestinyItems scope. Also You must have a valid Destiny account, and either be in a social space, in orbit or offline.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - item_id (
int): The item id. - character_id (
int): The character's id to equip the item to. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type associated with this player.
1182 async def equip_items( 1183 self, 1184 access_token: str, 1185 /, 1186 item_ids: list[int], 1187 character_id: int, 1188 membership_type: typedefs.IntAnd[enums.MembershipType], 1189 ) -> None: 1190 payload = { 1191 "itemIds": item_ids, 1192 "characterId": character_id, 1193 "membershipType": int(membership_type), 1194 } 1195 await self._request( 1196 RequestMethod.POST, 1197 "Destiny2/Actions/Items/EquipItems/", 1198 json=payload, 1199 auth=access_token, 1200 )
Equip multiple items to a character.
This requires the OAuth2: MoveEquipDestinyItems scope. Also You must have a valid Destiny account, and either be in a social space, in orbit or offline.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - item_ids (
list[int]): A list of item ids. - character_id (
int): The character's id to equip the item to. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type associated with this player.
1202 async def ban_clan_member( 1203 self, 1204 access_token: str, 1205 /, 1206 group_id: int, 1207 membership_id: int, 1208 membership_type: typedefs.IntAnd[enums.MembershipType], 1209 *, 1210 length: int = 0, 1211 comment: undefined.UndefinedOr[str] = undefined.UNDEFINED, 1212 ) -> None: 1213 payload = {"comment": str(comment), "length": length} 1214 await self._request( 1215 RequestMethod.POST, 1216 f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Ban/", 1217 json=payload, 1218 auth=access_token, 1219 )
Bans a member from the clan.
This request requires OAuth2: oauth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group id. - membership_id (
int): The member id to ban. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Other Parameters
- length (
int): An optional ban length. - comment (
aiobungie.UndefinedOr[str]): An optional comment to this ban. Default isUNDEFINED
1221 async def unban_clan_member( 1222 self, 1223 access_token: str, 1224 /, 1225 group_id: int, 1226 membership_id: int, 1227 membership_type: typedefs.IntAnd[enums.MembershipType], 1228 ) -> None: 1229 await self._request( 1230 RequestMethod.POST, 1231 f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Unban/", 1232 auth=access_token, 1233 )
Unban a member from the clan.
This request requires OAuth2: oauth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group id. - membership_id (
int): The member id to unban. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
1235 async def kick_clan_member( 1236 self, 1237 access_token: str, 1238 /, 1239 group_id: int, 1240 membership_id: int, 1241 membership_type: typedefs.IntAnd[enums.MembershipType], 1242 ) -> typedefs.JSONObject: 1243 resp = await self._request( 1244 RequestMethod.POST, 1245 f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Kick/", 1246 auth=access_token, 1247 ) 1248 assert isinstance(resp, dict) 1249 return resp
Kick a member from the clan.
This request requires OAuth2: oauth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group id. - membership_id (
int): The member id to kick. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the group that the member has been kicked from.
1251 async def edit_clan( 1252 self, 1253 access_token: str, 1254 /, 1255 group_id: int, 1256 *, 1257 name: typedefs.NoneOr[str] = None, 1258 about: typedefs.NoneOr[str] = None, 1259 motto: typedefs.NoneOr[str] = None, 1260 theme: typedefs.NoneOr[str] = None, 1261 tags: typedefs.NoneOr[collections.Sequence[str]] = None, 1262 is_public: typedefs.NoneOr[bool] = None, 1263 locale: typedefs.NoneOr[str] = None, 1264 avatar_image_index: typedefs.NoneOr[int] = None, 1265 membership_option: typedefs.NoneOr[ 1266 typedefs.IntAnd[enums.MembershipOption] 1267 ] = None, 1268 allow_chat: typedefs.NoneOr[bool] = None, 1269 chat_security: typedefs.NoneOr[typing.Literal[0, 1]] = None, 1270 call_sign: typedefs.NoneOr[str] = None, 1271 homepage: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None, 1272 enable_invite_messaging_for_admins: typedefs.NoneOr[bool] = None, 1273 default_publicity: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None, 1274 is_public_topic_admin: typedefs.NoneOr[bool] = None, 1275 ) -> None: 1276 payload = { 1277 "name": name, 1278 "about": about, 1279 "motto": motto, 1280 "theme": theme, 1281 "tags": tags, 1282 "isPublic": is_public, 1283 "avatarImageIndex": avatar_image_index, 1284 "isPublicTopicAdminOnly": is_public_topic_admin, 1285 "allowChat": allow_chat, 1286 "chatSecurity": chat_security, 1287 "callsign": call_sign, 1288 "homepage": homepage, 1289 "enableInvitationMessagingForAdmins": enable_invite_messaging_for_admins, 1290 "defaultPublicity": default_publicity, 1291 "locale": locale, 1292 } 1293 if membership_option is not None: 1294 payload["membershipOption"] = int(membership_option) 1295 1296 await self._request( 1297 RequestMethod.POST, 1298 f"GroupV2/{group_id}/Edit", 1299 json=payload, 1300 auth=access_token, 1301 )
Edit a clan.
Notes
- This request requires OAuth2: oauth2:
AdminGroupsscope. - All arguments will default to
Noneif not provided. This does not includeaccess_tokenandgroup_id
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group id to edit.
Other Parameters
- name (
aiobungie.typedefs.NoneOr[str]): The name to edit the clan with. - about (
aiobungie.typedefs.NoneOr[str]): The about section to edit the clan with. - motto (
aiobungie.typedefs.NoneOr[str]): The motto section to edit the clan with. - theme (
aiobungie.typedefs.NoneOr[str]): The theme name to edit the clan with. - tags (
aiobungie.typedefs.NoneOr[collections.Sequence[str]]): A sequence of strings to replace the clan tags with. - is_public (
aiobungie.typedefs.NoneOr[bool]): If provided and set toTrue, The clan will set to private. If provided and set toFalse, The clan will set to public whether it was or not. - locale (
aiobungie.typedefs.NoneOr[str]): The locale section to edit the clan with. - avatar_image_index (
aiobungie.typedefs.NoneOr[int]): The clan avatar image index to edit the clan with. - membership_option :
aiobungie.typedefs.NoneOr[aiobungie.typedefs.IntAnd[aiobungie.MembershipOption]]# noqa (E501 # Line too long): The clan membership option to edit it with. - allow_chat (
aiobungie.typedefs.NoneOr[bool]): If provided and set toTrue, The clan members will be allowed to chat. If provided and set toFalse, The clan members will not be allowed to chat. - chat_security (
aiobungie.typedefs.NoneOr[typing.Literal[0, 1]]): If provided and set to0, The clan chat security will be edited toGrouponly. If provided and set to1, The clan chat security will be edited toAdminonly. - call_sign (
aiobungie.typedefs.NoneOr[str]): The clan call sign to edit it with. - homepage (
aiobungie.typedefs.NoneOr[typing.Literal[0, 1, 2]]): If provided and set to0, The clan chat homepage will be edited toWall. If provided and set to1, The clan chat homepage will be edited toForum. If provided and set to0, The clan chat homepage will be edited toAllianceForum. - enable_invite_messaging_for_admins (
aiobungie.typedefs.NoneOr[bool]): ??? - default_publicity (
aiobungie.typedefs.NoneOr[typing.Literal[0, 1, 2]]): If provided and set to0, The clan chat publicity will be edited toPublic. If provided and set to1, The clan chat publicity will be edited toAlliance. If provided and set to2, The clan chat publicity will be edited toPrivate. - is_public_topic_admin (
aiobungie.typedefs.NoneOr[bool]): ???
1303 async def edit_clan_options( 1304 self, 1305 access_token: str, 1306 /, 1307 group_id: int, 1308 *, 1309 invite_permissions_override: typedefs.NoneOr[bool] = None, 1310 update_culture_permissionOverride: typedefs.NoneOr[bool] = None, 1311 host_guided_game_permission_override: typedefs.NoneOr[ 1312 typing.Literal[0, 1, 2] 1313 ] = None, 1314 update_banner_permission_override: typedefs.NoneOr[bool] = None, 1315 join_level: typedefs.NoneOr[typedefs.IntAnd[enums.ClanMemberType]] = None, 1316 ) -> None: 1317 payload = { 1318 "InvitePermissionOverride": invite_permissions_override, 1319 "UpdateCulturePermissionOverride": update_culture_permissionOverride, 1320 "HostGuidedGamePermissionOverride": host_guided_game_permission_override, 1321 "UpdateBannerPermissionOverride": update_banner_permission_override, 1322 "JoinLevel": int(join_level) if join_level else None, 1323 } 1324 1325 await self._request( 1326 RequestMethod.POST, 1327 f"GroupV2/{group_id}/EditFounderOptions", 1328 json=payload, 1329 auth=access_token, 1330 )
Edit the clan options.
Notes
- This request requires OAuth2: oauth2:
AdminGroupsscope. - All arguments will default to
Noneif not provided. This does not includeaccess_tokenandgroup_id
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group id.
Other Parameters
- invite_permissions_override (
aiobungie.typedefs.NoneOr[bool]): Minimum Member Level allowed to invite new members to group Always Allowed: Founder, Acting Founder True means admins have this power, false means they don't Default is False for clans, True for groups. - update_culture_permissionOverride (
aiobungie.typedefs.NoneOr[bool]): Minimum Member Level allowed to update group culture Always Allowed: Founder, Acting Founder True means admins have this power, false means they don't Default is False for clans, True for groups. - host_guided_game_permission_override (
aiobungie.typedefs.NoneOr[typing.Literal[0, 1, 2]]): Minimum Member Level allowed to host guided games Always Allowed: Founder, Acting Founder, Admin Allowed Overrides:0-> None,1-> Beginner2-> Member. Default is Member for clans, None for groups, although this means nothing for groups. - update_banner_permission_override (
aiobungie.typedefs.NoneOr[bool]): Minimum Member Level allowed to update banner Always Allowed: Founder, Acting Founder True means admins have this power, false means they don't Default is False for clans, True for groups. - join_level (
aiobungie.ClanMemberType): Level to join a member at when accepting an invite, application, or joining an open clan. Default isaiobungie.ClanMemberType.BEGINNER
1332 async def fetch_friends(self, access_token: str, /) -> typedefs.JSONObject: 1333 resp = await self._request( 1334 RequestMethod.GET, 1335 "Social/Friends/", 1336 auth=access_token, 1337 ) 1338 assert isinstance(resp, dict) 1339 return resp
Fetch bungie friend list.
This requests OAuth2: ReadUserData scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account.
Returns
aiobungie.typedefs.JSONObject: A JSON object of an array of the bungie friends's data.
1341 async def fetch_friend_requests(self, access_token: str, /) -> typedefs.JSONObject: 1342 resp = await self._request( 1343 RequestMethod.GET, 1344 "Social/Friends/Requests", 1345 auth=access_token, 1346 ) 1347 assert isinstance(resp, dict) 1348 return resp
Fetch pending bungie friend requests queue.
This requests OAuth2: ReadUserData scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account.
Returns
aiobungie.typedefs.JSONObject: A JSON object of incoming requests and outgoing requests.
1350 async def accept_friend_request(self, access_token: str, /, member_id: int) -> None: 1351 await self._request( 1352 RequestMethod.POST, 1353 f"Social/Friends/Requests/Accept/{member_id}", 1354 auth=access_token, 1355 )
Accepts a friend relationship with the target user. The user must be on your incoming friend request list.
This request requires OAuth2: BnetWrite scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - member_id (
int): The member's id to accept.
1357 async def send_friend_request(self, access_token: str, /, member_id: int) -> None: 1358 await self._request( 1359 RequestMethod.POST, 1360 f"Social/Friends/Add/{member_id}", 1361 auth=access_token, 1362 )
Requests a friend relationship with the target user.
This request requires OAuth2: BnetWrite scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - member_id (
int): The member's id to send the request to.
1364 async def decline_friend_request( 1365 self, access_token: str, /, member_id: int 1366 ) -> None: 1367 await self._request( 1368 RequestMethod.POST, 1369 f"Social/Friends/Requests/Decline/{member_id}", 1370 auth=access_token, 1371 )
Decline a friend request with the target user. The user must be in your incoming friend request list.
This request requires OAuth2: BnetWrite scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - member_id (
int): The member's id to decline.
1373 async def remove_friend(self, access_token: str, /, member_id: int) -> None: 1374 await self._request( 1375 RequestMethod.POST, 1376 f"Social/Friends/Remove/{member_id}", 1377 auth=access_token, 1378 )
Removes a friend from your friend list. The user must be in your friend list.
This request requires OAuth2: BnetWrite scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - member_id (
int): The member's id to remove.
1380 async def remove_friend_request(self, access_token: str, /, member_id: int) -> None: 1381 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1382 await self._request( 1383 RequestMethod.POST, 1384 f"Social/Friends/Requests/Remove/{member_id}", 1385 auth=access_token, 1386 )
Removes a friend from your friend list requests. The user must be in your outgoing request list.
.. note : This request requires OAuth2: BnetWrite scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - member_id (
int): The member's id to remove from the requested friend list.
1388 async def approve_all_pending_group_users( 1389 self, 1390 access_token: str, 1391 /, 1392 group_id: int, 1393 message: undefined.UndefinedOr[str] = undefined.UNDEFINED, 1394 ) -> None: 1395 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1396 await self._request( 1397 RequestMethod.POST, 1398 f"GroupV2/{group_id}/Members/ApproveAll", 1399 auth=access_token, 1400 json={"message": str(message)}, 1401 )
Approve all pending users for the given group id.
This request requires OAuth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The given group id.
Other Parameters
- message (
aiobungie.UndefinedOr[str]): An optional message to send with the request. Default isUNDEFINED.
1403 async def deny_all_pending_group_users( 1404 self, 1405 access_token: str, 1406 /, 1407 group_id: int, 1408 *, 1409 message: undefined.UndefinedOr[str] = undefined.UNDEFINED, 1410 ) -> None: 1411 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1412 await self._request( 1413 RequestMethod.POST, 1414 f"GroupV2/{group_id}/Members/DenyAll", 1415 auth=access_token, 1416 json={"message": str(message)}, 1417 )
Deny all pending users for the given group id.
This request requires OAuth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The given group id.
Other Parameters
- message (
aiobungie.UndefinedOr[str]): An optional message to send with the request. Default isUNDEFINED.
1419 async def add_optional_conversation( 1420 self, 1421 access_token: str, 1422 /, 1423 group_id: int, 1424 *, 1425 name: undefined.UndefinedOr[str] = undefined.UNDEFINED, 1426 security: typing.Literal[0, 1] = 0, 1427 ) -> None: 1428 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1429 payload = {"chatName": str(name), "chatSecurity": security} 1430 await self._request( 1431 RequestMethod.POST, 1432 f"GroupV2/{group_id}/OptionalConversations/Add", 1433 json=payload, 1434 auth=access_token, 1435 )
Add a new chat channel to a group.
This request requires OAuth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The given group id.
Other parameters
name: aiobungie.UndefinedOr[str]
The chat name. Default to UNDEFINED
security: typing.Literal[0, 1]
The security level of the chat.
If provided and set to 0, It will be to `Group` only.
If provided and set to 1, It will be `Admins` only.
Default is `0`
1437 async def edit_optional_conversation( 1438 self, 1439 access_token: str, 1440 /, 1441 group_id: int, 1442 conversation_id: int, 1443 *, 1444 name: undefined.UndefinedOr[str] = undefined.UNDEFINED, 1445 security: typing.Literal[0, 1] = 0, 1446 enable_chat: bool = False, 1447 ) -> None: 1448 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1449 payload = { 1450 "chatEnabled": enable_chat, 1451 "chatName": str(name), 1452 "chatSecurity": security, 1453 } 1454 await self._request( 1455 RequestMethod.POST, 1456 f"GroupV2/{group_id}/OptionalConversations/Edit/{conversation_id}", 1457 json=payload, 1458 auth=access_token, 1459 )
Edit the settings of this chat channel.
This request requires OAuth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The given group id. - conversation_id (
int): The conversation/chat id.
Other parameters
name: aiobungie.UndefinedOr[str]
The new chat name. Default to UNDEFINED
security: typing.Literal[0, 1]
The new security level of the chat.
If provided and set to 0, It will be to `Group` only.
If provided and set to 1, It will be `Admins` only.
Default is `0`
enable_chat : bool
Whether to enable chatting or not.
If set to True then chatting will be enabled. Otherwise it will be disabled.
1461 async def transfer_item( 1462 self, 1463 access_token: str, 1464 /, 1465 item_id: int, 1466 item_hash: int, 1467 character_id: int, 1468 member_type: typedefs.IntAnd[enums.MembershipType], 1469 *, 1470 stack_size: int = 1, 1471 vault: bool = False, 1472 ) -> None: 1473 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1474 payload = { 1475 "characterId": character_id, 1476 "membershipType": int(member_type), 1477 "itemId": item_id, 1478 "itemReferenceHash": item_hash, 1479 "stackSize": stack_size, 1480 "transferToVault": vault, 1481 } 1482 await self._request( 1483 RequestMethod.POST, 1484 "Destiny2/Actions/Items/TransferItem", 1485 json=payload, 1486 auth=access_token, 1487 )
Transfer an item from / to your vault.
Notes
- This method requires OAuth2: MoveEquipDestinyItems scope.
- This method requires both item id and hash.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - item_id (
int): The item instance id you to transfer. - item_hash (
int): The item hash. - character_id (
int): The character id to transfer the item from/to. - member_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The user membership type.
Other Parameters
- stack_size (
int): The item stack size. - vault (
bool): Whether to transfer this item to your vault or not. Defaults toFalse.
1489 async def pull_item( 1490 self, 1491 access_token: str, 1492 /, 1493 item_id: int, 1494 item_hash: int, 1495 character_id: int, 1496 member_type: typedefs.IntAnd[enums.MembershipType], 1497 *, 1498 stack_size: int = 1, 1499 vault: bool = False, 1500 ) -> None: 1501 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1502 payload = { 1503 "characterId": character_id, 1504 "membershipType": int(member_type), 1505 "itemId": item_id, 1506 "itemReferenceHash": item_hash, 1507 "stackSize": stack_size, 1508 "transferToVault": vault, 1509 } 1510 await self._request( 1511 RequestMethod.POST, 1512 "Destiny2/Actions/Items/PullFromPostmaster", 1513 json=payload, 1514 auth=access_token, 1515 )
pull an item from the postmaster.
Notes
- This method requires OAuth2: MoveEquipDestinyItems scope.
- This method requires both item id and hash.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - item_id (
int): The item instance id to pull. - item_hash (
int): The item hash. - character_id (
int): The character id to pull the item to. - member_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The user membership type.
Other Parameters
- stack_size (
int): The item stack size. - vault (
bool): Whether to pill this item to your vault or not. Defaults toFalse.
1517 async def fetch_fireteams( 1518 self, 1519 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 1520 *, 1521 platform: typedefs.IntAnd[ 1522 fireteams.FireteamPlatform 1523 ] = fireteams.FireteamPlatform.ANY, 1524 language: typing.Union[ 1525 fireteams.FireteamLanguage, str 1526 ] = fireteams.FireteamLanguage.ALL, 1527 date_range: typedefs.IntAnd[ 1528 fireteams.FireteamDate 1529 ] = fireteams.FireteamDate.ALL, 1530 page: int = 0, 1531 slots_filter: int = 0, 1532 ) -> typedefs.JSONObject: 1533 resp = await self._request( 1534 RequestMethod.GET, 1535 f"Fireteam/Search/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{page}/?langFilter={str(language)}", # noqa: E501 Line too long 1536 ) 1537 assert isinstance(resp, dict) 1538 return resp
Fetch public Bungie fireteams with open slots.
Parameters
- activity_type (
aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]): The fireteam activity type.
Other Parameters
- platform (
aiobungie.typedefs.IntAnd[FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults toaiobungie.crates.FireteamPlatform.ANYwhich returns all platforms. - language (
typing.Union[FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults toaiobungie.crates.FireteamLanguage.ALL - date_range (
aiobungie.typedefs.IntAnd[aiobungie.FireteamDate]): An integer to filter the date range of the returned fireteams. Defaults toaiobungie.FireteamDate.ALL. - page (
int): The page number. By default its0which returns all available activities. - slots_filter (
int): Filter the returned fireteams based on available slots. Default is0
Returns
aiobungie.typedefs.JSONObject: A JSON object of the fireteam details.
1540 async def fetch_available_clan_fireteams( 1541 self, 1542 access_token: str, 1543 group_id: int, 1544 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 1545 *, 1546 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1547 language: typing.Union[fireteams.FireteamLanguage, str], 1548 date_range: typedefs.IntAnd[ 1549 fireteams.FireteamDate 1550 ] = fireteams.FireteamDate.ALL, 1551 page: int = 0, 1552 public_only: bool = False, 1553 slots_filter: int = 0, 1554 ) -> typedefs.JSONObject: 1555 resp = await self._request( 1556 RequestMethod.GET, 1557 f"Fireteam/Clan/{group_id}/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{public_only}/{page}", # noqa: E501 1558 json={"langFilter": str(language)}, 1559 auth=access_token, 1560 ) 1561 assert isinstance(resp, dict) 1562 return resp
Fetch a clan's fireteams with open slots.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group/clan id of the fireteam. - activity_type (
aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]): The fireteam activity type.
Other Parameters
- platform (
aiobungie.typedefs.IntAnd[FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults toaiobungie.crates.FireteamPlatform.ANYwhich returns all platforms. - language (
typing.Union[FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults toaiobungie.crates.FireteamLanguage.ALL - date_range (
aiobungie.typedefs.IntAnd[aiobungie.FireteamDate]): An integer to filter the date range of the returned fireteams. Defaults toaiobungie.FireteamDate.ALL. - page (
int): The page number. By default its0which returns all available activities. - public_only (
bool): If set to True, Then only public fireteams will be returned. - slots_filter (
int): Filter the returned fireteams based on available slots. Default is0
Returns
aiobungie.typedefs.JSONObject: A JSON object of the fireteams detail.
1564 async def fetch_clan_fireteam( 1565 self, access_token: str, fireteam_id: int, group_id: int 1566 ) -> typedefs.JSONObject: 1567 resp = await self._request( 1568 RequestMethod.GET, 1569 f"Fireteam/Clan/{group_id}/Summary/{fireteam_id}", 1570 auth=access_token, 1571 ) 1572 assert isinstance(resp, dict) 1573 return resp
Fetch a specific clan fireteam.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group/clan id to fetch the fireteam from. - fireteam_id (
int): The fireteam id to fetch.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the fireteam details.
1575 async def fetch_my_clan_fireteams( 1576 self, 1577 access_token: str, 1578 group_id: int, 1579 *, 1580 include_closed: bool = True, 1581 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1582 language: typing.Union[fireteams.FireteamLanguage, str], 1583 filtered: bool = True, 1584 page: int = 0, 1585 ) -> typedefs.JSONObject: 1586 payload = {"groupFilter": filtered, "langFilter": str(language)} 1587 1588 resp = await self._request( 1589 RequestMethod.GET, 1590 f"Fireteam/Clan/{group_id}/My/{int(platform)}/{include_closed}/{page}", 1591 json=payload, 1592 auth=access_token, 1593 ) 1594 assert isinstance(resp, dict) 1595 return resp
Fetch a clan's fireteams with open slots.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group/clan id to fetch.
Other Parameters
- include_closed (
bool): If provided and set toTrue, It will also return closed fireteams. If provided and set toFalse, It will only return public fireteams. Default isTrue. - platform (
aiobungie.typedefs.IntAnd[FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults toaiobungie.crates.FireteamPlatform.ANYwhich returns all platforms. - language (
typing.Union[FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults toaiobungie.crates.FireteamLanguage.ALL - filtered (
bool): If set toTrue, it will filter by clan. Otherwise not. Default isTrue. - page (
int): The page number. By default its0which returns all available activities.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the fireteams detail.
1597 async def fetch_private_clan_fireteams( 1598 self, access_token: str, group_id: int, / 1599 ) -> int: 1600 resp = await self._request( 1601 RequestMethod.GET, 1602 f"Fireteam/Clan/{group_id}/ActiveCount", 1603 auth=access_token, 1604 ) 1605 assert isinstance(resp, int) 1606 return resp
Fetch the active count of the clan fireteams that are only private.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group/clan id.
Returns
int: The active fireteams count. Max value returned is 25.
1608 async def fetch_post_activity(self, instance_id: int, /) -> typedefs.JSONObject: 1609 resp = await self._request( 1610 RequestMethod.GET, f"Destiny2/Stats/PostGameCarnageReport/{instance_id}" 1611 ) 1612 assert isinstance(resp, dict) 1613 return resp
Fetch a post activity details.
Parameters
- instance_id (
int): The activity instance id.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the post activity.
1615 async def search_entities( 1616 self, name: str, entity_type: str, *, page: int = 0 1617 ) -> typedefs.JSONObject: 1618 resp = await self._request( 1619 RequestMethod.GET, 1620 f"Destiny2/Armory/Search/{entity_type}/{name}/", 1621 json={"page": page}, 1622 ) 1623 assert isinstance(resp, dict) 1624 return resp
Search for Destiny2 entities given a name and its type.
Parameters
- name (
str): The name of the entity, i.e., Thunderlord, One thousand voices. - entity_type (
str): The type of the entity, AKA Definition, For an exampleDestinyInventoryItemDefinition
Other Parameters
- page (
int): An optional page to return. Default to 0.
Returns
aiobungie.typedefs.JSONObject: A JSON object contains details about the searched term.
1626 async def fetch_unique_weapon_history( 1627 self, 1628 membership_id: int, 1629 character_id: int, 1630 membership_type: typedefs.IntAnd[enums.MembershipType], 1631 ) -> typedefs.JSONObject: 1632 resp = await self._request( 1633 RequestMethod.GET, 1634 f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/UniqueWeapons/", 1635 ) 1636 assert isinstance(resp, dict) 1637 return resp
Fetch details about unique weapon usage for a character. Includes all exotics.
Parameters
- membership_id (
int): The Destiny user membership id. - character_id (
int): The character id to retrieve. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny user's membership type.
Returns
aiobungie.typedefs.JSONObject: A JSON object contains details about the returned weapons.
1639 async def fetch_item( 1640 self, 1641 member_id: int, 1642 item_id: int, 1643 membership_type: typedefs.IntAnd[enums.MembershipType], 1644 components: list[enums.ComponentType], 1645 ) -> typedefs.JSONObject: 1646 collector = _collect_components(components) 1647 1648 resp = await self._request( 1649 RequestMethod.GET, 1650 f"Destiny2/{int(membership_type)}/Profile/{member_id}/Item/{item_id}/?components={collector}", 1651 ) 1652 assert isinstance(resp, dict) 1653 return resp
Fetch an instanced Destiny 2 item's details.
Parameters
- member_id (
int): The membership id of the Destiny 2 player. - item_id (
int): The instance id of the item. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type of the Destiny 2 player. - components (
list[aiobungie.ComponentType]): A list of components to retrieve.
Returns
aiobungie.typedefs.JSONObject: A JSON object response contains the fetched item with its components.
1655 async def fetch_clan_weekly_rewards(self, clan_id: int, /) -> typedefs.JSONObject: 1656 resp = await self._request( 1657 RequestMethod.GET, f"Destiny2/Clan/{clan_id}/WeeklyRewardState/" 1658 ) 1659 assert isinstance(resp, dict) 1660 return resp
Fetch the weekly reward state for a clan.
Parameters
- clan_id (
int): The clan id.
Returns
aiobungie.typedefs.JSONObject: A JSON response of the clan rewards state.
1662 async def fetch_available_locales(self) -> typedefs.JSONObject: 1663 resp = await self._request( 1664 RequestMethod.GET, "Destiny2/Manifest/DestinyLocaleDefinition/" 1665 ) 1666 assert isinstance(resp, dict) 1667 return resp
Fetch available locales at Bungie.
Returns
aiobungie.typedefs.JSONObject: A JSON object contains a list of all available localization cultures.
1669 async def fetch_common_settings(self) -> typedefs.JSONObject: 1670 resp = await self._request(RequestMethod.GET, "Settings") 1671 assert isinstance(resp, dict) 1672 return resp
Fetch the common settings used by Bungie's envirotment.
Returns
aiobungie.typedefs.JSONObject: The common settings JSON object.
1674 async def fetch_user_systems_overrides(self) -> typedefs.JSONObject: 1675 resp = await self._request(RequestMethod.GET, "UserSystemOverrides") 1676 assert isinstance(resp, dict) 1677 return resp
Fetch a user's specific system overrides.
Returns
aiobungie.typedefs.JSONObject: The system overrides JSON object.
1679 async def fetch_global_alerts( 1680 self, *, include_streaming: bool = False 1681 ) -> typedefs.JSONArray: 1682 resp = await self._request( 1683 RequestMethod.GET, f"GlobalAlerts/?includestreaming={include_streaming}" 1684 ) 1685 assert isinstance(resp, list) 1686 return resp
Fetch any active global alerts.
Parameters
- include_streaming (
bool): If True, the returned results will include streaming alerts. Default is False.
Returns
aiobungie.typedefs.JSONArray: A JSON array of the global alerts objects.
1688 async def awainitialize_request( 1689 self, 1690 access_token: str, 1691 type: typing.Literal[0, 1], 1692 membership_type: typedefs.IntAnd[enums.MembershipType], 1693 /, 1694 *, 1695 affected_item_id: typing.Optional[int] = None, 1696 character_id: typing.Optional[int] = None, 1697 ) -> typedefs.JSONObject: 1698 body = {"type": type, "membershipType": int(membership_type)} 1699 1700 if affected_item_id is not None: 1701 body["affectedItemId"] = affected_item_id 1702 1703 if character_id is not None: 1704 body["characterId"] = character_id 1705 1706 resp = await self._request( 1707 RequestMethod.POST, "Destiny2/Awa/Initialize", json=body, auth=access_token 1708 ) 1709 assert isinstance(resp, dict) 1710 return resp
Initialize a request to perform an advanced write action.
OAuth2: AdvancedWriteActions application scope is required to perform this request.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - type (
typing.Literal[0, 1]): Type of the advanced write action. Its either 0 or 1. If set to 0 that means itNone. Otherwise if 1 that means its insert plugs. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny membership type of the account to modify.
Other Parameters
- affected_item_id (
typing.Optional[int]): Item instance ID the action shall be applied to. This is optional for all but a new AwaType values. - character_id (
typing.Optional[int]): The Destiny character ID to perform this action on.
Returns
aiobungie.typedefs.JSONObject: A JSON object response.
1712 async def awaget_action_token( 1713 self, access_token: str, correlation_id: str, / 1714 ) -> typedefs.JSONObject: 1715 resp = await self._request( 1716 RequestMethod.POST, 1717 f"Destiny2/Awa/GetActionToken/{correlation_id}", 1718 auth=access_token, 1719 ) 1720 assert isinstance(resp, dict) 1721 return resp
Returns the action token if user approves the request.
OAuth2: AdvancedWriteActions application scope is required to perform this request.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - correlation_id (
str): The identifier for the advanced write action request.
Returns
aiobungie.typedefs.JSONObject: A JSON object response.
1741 async def fetch_vendors( 1742 self, 1743 access_token: str, 1744 character_id: int, 1745 membership_id: int, 1746 membership_type: typedefs.IntAnd[enums.MembershipType], 1747 /, 1748 components: list[enums.ComponentType], 1749 filter: typing.Optional[int] = None, 1750 ) -> typedefs.JSONObject: 1751 components_ = _collect_components(components) 1752 route = ( 1753 f"Destiny2/{int(membership_type)}/Profile/{membership_id}" 1754 f"/Character/{character_id}/Vendors/?components={components_}" 1755 ) 1756 1757 if filter is not None: 1758 route = route + f"&filter={filter}" 1759 1760 resp = await self._request( 1761 RequestMethod.GET, 1762 route, 1763 auth=access_token, 1764 ) 1765 assert isinstance(resp, dict) 1766 return resp
Get currently available vendors from the list of vendors that can possibly have rotating inventory.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - character_id (
int): The character ID to return the vendor info for. - membership_id (
int): The Destiny membership id to return the vendor info for. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny membership type to return the vendor info for. - components (
list[aiobungie.ComponentType]): A list of vendor components to collect and return.
Other Parameters
- filter (
int): Filters the type of items returned from the vendor. This can be left toNone.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the vendor response.
1768 async def fetch_vendor( 1769 self, 1770 access_token: str, 1771 character_id: int, 1772 membership_id: int, 1773 membership_type: typedefs.IntAnd[enums.MembershipType], 1774 vendor_hash: int, 1775 /, 1776 components: list[enums.ComponentType], 1777 ) -> typedefs.JSONObject: 1778 components_ = _collect_components(components) 1779 resp = await self._request( 1780 RequestMethod.GET, 1781 ( 1782 f"Destiny2/{int(membership_type)}/Profile/{membership_id}" 1783 f"/Character/{character_id}/Vendors/{vendor_hash}/?components={components_}" 1784 ), 1785 auth=access_token, 1786 ) 1787 assert isinstance(resp, dict) 1788 return resp
Fetch details for a specific vendor.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - character_id (
int): The character ID to return the vendor info for. - membership_id (
int): The Destiny membership id to return the vendor info for. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny membership type to return the vendor info for. - vendor_hash (
int): The vendor hash to return the details for. - components (
list[aiobungie.ComponentType]): A list of vendor components to collect and return.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the vendor response.
1790 async def fetch_application_api_usage( 1791 self, 1792 access_token: str, 1793 application_id: int, 1794 /, 1795 *, 1796 start: typing.Optional[datetime.datetime] = None, 1797 end: typing.Optional[datetime.datetime] = None, 1798 ) -> typedefs.JSONObject: 1799 end_date, start_date = time.parse_date_range(end, start) 1800 resp = await self._request( 1801 RequestMethod.GET, 1802 f"App/ApiUsage/{application_id}/?end={end_date}&start={start_date}", 1803 auth=access_token, 1804 ) 1805 assert isinstance(resp, dict) 1806 return resp
Fetch a Bungie application's API usage.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - application_id (
int): The application id to get.
Other Parameters
start (
typing.Optional[datetime.datetime]): A datetime object can be used to collect the start of the application usage. This is limited and can go back to 30 days maximum.If this is left to
None. It will return the last 24 hours.end (
typing.Optional[datetime.datetime]): A datetime object can be used to collect the end of the application usage.If this is left to
None. It will returnnow.
Example
import datetime
# Fetch data from 2021 Dec 10th to 2021 Dec 20th
await fetch_application_api_usage(
start=datetime.datetime(2021, 12, 10), end=datetime.datetime(2021, 12, 20)
)
Returns
aiobungie.typedefs.JSONObject: A JSON object of the application usage details.
1808 async def fetch_bungie_applications(self) -> typedefs.JSONArray: 1809 resp = await self._request(RequestMethod.GET, "App/FirstParty") 1810 assert isinstance(resp, list) 1811 return resp
Fetch details for applications created by Bungie.
Returns
aiobungie.typedefs.JSONArray: An array of Bungie created applications.
1818 async def fetch_content_by_id( 1819 self, id: int, locale: str, /, *, head: bool = False 1820 ) -> typedefs.JSONObject: 1821 resp = await self._request( 1822 RequestMethod.GET, 1823 f"Content/GetContentById/{id}/{locale}/", 1824 json={"head": head}, 1825 ) 1826 assert isinstance(resp, dict) 1827 return resp
1829 async def fetch_content_by_tag_and_type( 1830 self, locale: str, tag: str, type: str, *, head: bool = False 1831 ) -> typedefs.JSONObject: 1832 resp = await self._request( 1833 RequestMethod.GET, 1834 f"Content/GetContentByTagAndType/{tag}/{type}/{locale}/", 1835 json={"head": head}, 1836 ) 1837 assert isinstance(resp, dict) 1838 return resp
1840 async def search_content_with_text( 1841 self, 1842 locale: str, 1843 /, 1844 content_type: str, 1845 search_text: str, 1846 tag: str, 1847 *, 1848 page: undefined.UndefinedOr[int] = undefined.UNDEFINED, 1849 source: undefined.UndefinedOr[str] = undefined.UNDEFINED, 1850 ) -> typedefs.JSONObject: 1851 body: typedefs.JSONObject = {} 1852 1853 body["ctype"] = content_type 1854 body["searchtext"] = search_text 1855 body["tag"] = tag 1856 1857 if page is not undefined.UNDEFINED: 1858 body["currentpage"] = page 1859 else: 1860 body["currentpage"] = 1 1861 1862 if source is not undefined.UNDEFINED: 1863 body["source"] = source 1864 else: 1865 source = "" 1866 resp = await self._request( 1867 RequestMethod.GET, f"Content/Search/{locale}/", json=body 1868 ) 1869 assert isinstance(resp, dict) 1870 return resp
1872 async def search_content_by_tag_and_type( 1873 self, 1874 locale: str, 1875 tag: str, 1876 type: str, 1877 *, 1878 page: undefined.UndefinedOr[int] = undefined.UNDEFINED, 1879 ) -> typedefs.JSONObject: 1880 body: typedefs.JSONObject = {} 1881 body["currentpage"] = 1 if page is undefined.UNDEFINED else page 1882 resp = await self._request( 1883 RequestMethod.GET, 1884 f"Content/SearchContentByTagAndType/{tag}/{type}/{locale}/", 1885 json=body, 1886 ) 1887 assert isinstance(resp, dict) 1888 return resp
1899 async def fetch_topics_page( 1900 self, 1901 category_filter: int, 1902 group: int, 1903 date_filter: int, 1904 sort: typing.Union[str, bytes], 1905 *, 1906 page: undefined.UndefinedOr[int] = undefined.UNDEFINED, 1907 locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.UNDEFINED, 1908 tag_filter: undefined.UndefinedOr[str] = undefined.UNDEFINED, 1909 ) -> typedefs.JSONObject: 1910 body: typedefs.JSONObject = {} 1911 if locales is not undefined.UNDEFINED: 1912 body["locales"] = ",".join(str(locales)) 1913 else: 1914 body["locales"] = ",".join([]) 1915 1916 if tag_filter is not undefined.UNDEFINED: 1917 body["tagstring"] = tag_filter 1918 else: 1919 body["tagstring"] = "" 1920 1921 page = 0 if page is not undefined.UNDEFINED else page 1922 1923 resp = await self._request( 1924 RequestMethod.GET, 1925 f"Forum/GetTopicsPaged/{page}/{0}/{group}/{sort!s}/{date_filter}/{category_filter}/", 1926 json=body, 1927 ) 1928 assert isinstance(resp, dict) 1929 return resp
1931 async def fetch_core_topics_page( 1932 self, 1933 category_filter: int, 1934 date_filter: int, 1935 sort: typing.Union[str, bytes], 1936 *, 1937 page: undefined.UndefinedOr[int] = undefined.UNDEFINED, 1938 locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.UNDEFINED, 1939 ) -> typedefs.JSONObject: 1940 body: typedefs.JSONObject = {} 1941 1942 if locales is not undefined.UNDEFINED: 1943 body["locales"] = ",".join(str(locales)) 1944 else: 1945 body["locales"] = ",".join([]) 1946 1947 resp = await self._request( 1948 RequestMethod.GET, 1949 f"Forum/GetCoreTopicsPaged/{0 if page is undefined.UNDEFINED else page}" 1950 f"/{sort!s}/{date_filter}/{category_filter}/", 1951 json=body, 1952 ) 1953 assert isinstance(resp, dict) 1954 return resp
1956 async def fetch_posts_threaded_page( 1957 self, 1958 parent_post: bool, 1959 page: int, 1960 page_size: int, 1961 parent_post_id: int, 1962 reply_size: int, 1963 root_thread_mode: bool, 1964 sort_mode: int, 1965 show_banned: typing.Optional[str] = None, 1966 ) -> typedefs.JSONObject: 1967 resp = await self._request( 1968 RequestMethod.GET, 1969 f"Forum/GetPostsThreadedPaged/{parent_post}/{page}/" 1970 f"{page_size}/{reply_size}/{parent_post_id}/{root_thread_mode}/{sort_mode}/", 1971 json={"showbanned": show_banned}, 1972 ) 1973 assert isinstance(resp, dict) 1974 return resp
1976 async def fetch_posts_threaded_page_from_child( 1977 self, 1978 child_id: bool, 1979 page: int, 1980 page_size: int, 1981 reply_size: int, 1982 root_thread_mode: bool, 1983 sort_mode: int, 1984 show_banned: typing.Optional[str] = None, 1985 ) -> typedefs.JSONObject: 1986 resp = await self._request( 1987 RequestMethod.GET, 1988 f"Forum/GetPostsThreadedPagedFromChild/{child_id}/" 1989 f"{page}/{page_size}/{reply_size}/{root_thread_mode}/{sort_mode}/", 1990 json={"showbanned": show_banned}, 1991 ) 1992 assert isinstance(resp, dict) 1993 return resp
1995 async def fetch_post_and_parent( 1996 self, child_id: int, /, *, show_banned: typing.Optional[str] = None 1997 ) -> typedefs.JSONObject: 1998 resp = await self._request( 1999 RequestMethod.GET, 2000 f"Forum/GetPostAndParent/{child_id}/", 2001 json={"showbanned": show_banned}, 2002 ) 2003 assert isinstance(resp, dict) 2004 return resp
2006 async def fetch_posts_and_parent_awaiting( 2007 self, child_id: int, /, *, show_banned: typing.Optional[str] = None 2008 ) -> typedefs.JSONObject: 2009 resp = await self._request( 2010 RequestMethod.GET, 2011 f"Forum/GetPostAndParentAwaitingApproval/{child_id}/", 2012 json={"showbanned": show_banned}, 2013 ) 2014 assert isinstance(resp, dict) 2015 return resp
2045 async def fetch_recommended_groups( 2046 self, 2047 accecss_token: str, 2048 /, 2049 *, 2050 date_range: int = 0, 2051 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 2052 ) -> typedefs.JSONArray: 2053 resp = await self._request( 2054 RequestMethod.POST, 2055 f"GroupV2/Recommended/{int(group_type)}/{date_range}/", 2056 auth=accecss_token, 2057 ) 2058 assert isinstance(resp, list) 2059 return resp
2066 async def fetch_user_clan_invite_setting( 2067 self, 2068 access_token: str, 2069 /, 2070 membership_type: typedefs.IntAnd[enums.MembershipType], 2071 ) -> bool: 2072 resp = await self._request( 2073 RequestMethod.GET, 2074 f"GroupV2/GetUserClanInviteSetting/{int(membership_type)}/", 2075 auth=access_token, 2076 ) 2077 assert isinstance(resp, bool) 2078 return resp
2080 async def fetch_banned_group_members( 2081 self, access_token: str, group_id: int, /, *, page: int = 1 2082 ) -> typedefs.JSONObject: 2083 resp = await self._request( 2084 RequestMethod.GET, 2085 f"GroupV2/{group_id}/Banned/?currentpage={page}", 2086 auth=access_token, 2087 ) 2088 assert isinstance(resp, dict) 2089 return resp
2091 async def fetch_pending_group_memberships( 2092 self, access_token: str, group_id: int, /, *, current_page: int = 1 2093 ) -> typedefs.JSONObject: 2094 resp = await self._request( 2095 RequestMethod.GET, 2096 f"GroupV2/{group_id}/Members/Pending/?currentpage={current_page}", 2097 auth=access_token, 2098 ) 2099 assert isinstance(resp, dict) 2100 return resp
2102 async def fetch_invited_group_memberships( 2103 self, access_token: str, group_id: int, /, *, current_page: int = 1 2104 ) -> typedefs.JSONObject: 2105 resp = await self._request( 2106 RequestMethod.GET, 2107 f"GroupV2/{group_id}/Members/InvitedIndividuals/?currentpage={current_page}", 2108 auth=access_token, 2109 ) 2110 assert isinstance(resp, dict) 2111 return resp
2113 async def invite_member_to_group( 2114 self, 2115 access_token: str, 2116 /, 2117 group_id: int, 2118 membership_id: int, 2119 membership_type: typedefs.IntAnd[enums.MembershipType], 2120 *, 2121 message: undefined.UndefinedOr[str] = undefined.UNDEFINED, 2122 ) -> typedefs.JSONObject: 2123 resp = await self._request( 2124 RequestMethod.POST, 2125 f"GroupV2/{group_id}/Members/IndividualInvite/{int(membership_type)}/{membership_id}/", 2126 auth=access_token, 2127 json={"message": str(message)}, 2128 ) 2129 assert isinstance(resp, dict) 2130 return resp
2132 async def cancel_group_member_invite( 2133 self, 2134 access_token: str, 2135 /, 2136 group_id: int, 2137 membership_id: int, 2138 membership_type: typedefs.IntAnd[enums.MembershipType], 2139 ) -> typedefs.JSONObject: 2140 resp = await self._request( 2141 RequestMethod.POST, 2142 f"GroupV2/{group_id}/Members/IndividualInviteCancel/{int(membership_type)}/{membership_id}/", 2143 auth=access_token, 2144 ) 2145 assert isinstance(resp, dict) 2146 return resp
2153 async def fetch_historical_stats( 2154 self, 2155 character_id: int, 2156 membership_id: int, 2157 membership_type: typedefs.IntAnd[enums.MembershipType], 2158 day_start: datetime.datetime, 2159 day_end: datetime.datetime, 2160 groups: list[typedefs.IntAnd[enums.StatsGroupType]], 2161 modes: collections.Sequence[typedefs.IntAnd[enums.GameMode]], 2162 *, 2163 period_type: enums.PeriodType = enums.PeriodType.ALL_TIME, 2164 ) -> typedefs.JSONObject: 2165 end, start = time.parse_date_range(day_end, day_start) 2166 resp = await self._request( 2167 RequestMethod.GET, 2168 f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/", 2169 json={ 2170 "dayend": end, 2171 "daystart": start, 2172 "groups": [str(int(group)) for group in groups], 2173 "modes": [str(int(mode)) for mode in modes], 2174 "periodType": int(period_type), 2175 }, 2176 ) 2177 assert isinstance(resp, dict) 2178 return resp
Fetch historical stats for a specific membership character.
Parameters
- character_id (
int): The character ID to return the stats for. - membership_id (
int): The Destiny membership id to return the stats for. - membership_type (
aiobungie.MembershipType | int): The Destiny membership type to return the stats for. - day_start (
datetime.datetime): The start of the day to return the stats for. - day_end (
datetime.datetime): The end of the day to return the stats for. - groups (
list[aiobungie.StatsGroupType]): A list of stats groups to return. - modes (
list[aiobungie.GameMode | int]): A list of game modes to return. - period_type (
aiobungie.enums.PeriodType): The period type to return the stats for. This will returnALL_TIMEby default if not modified.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the historical stats.
2180 async def fetch_historical_stats_for_account( 2181 self, 2182 membership_id: int, 2183 membership_type: typedefs.IntAnd[enums.MembershipType], 2184 groups: list[typedefs.IntAnd[enums.StatsGroupType]], 2185 ) -> typedefs.JSONObject: 2186 resp = await self._request( 2187 RequestMethod.GET, 2188 f"Destiny2/{int(membership_type)}/Account/{membership_id}/Stats/", 2189 json={"groups": [str(int(group)) for group in groups]}, 2190 ) 2191 assert isinstance(resp, dict) 2192 return resp
Fetch historical stats for an account's membership.
Parameters
- membership_id (
int): The Destiny membership id to return the stats for. - membership_type (
aiobungie.MembershipType | int): The Destiny membership type to return the stats for. - groups (
list[aiobungie.StatsGroupType]): A list of stats groups to return.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the historical stats for the account. This includes both the character and account stats.
2194 async def fetch_aggregated_activity_stats( 2195 self, 2196 character_id: int, 2197 membership_id: int, 2198 membership_type: typedefs.IntAnd[enums.MembershipType], 2199 /, 2200 ) -> typedefs.JSONObject: 2201 resp = await self._request( 2202 RequestMethod.GET, 2203 f"Destiny2/{int(membership_type)}/Account/{membership_id}/" 2204 f"Character/{character_id}/Stats/AggregateActivityStats/", 2205 ) 2206 assert isinstance(resp, dict) 2207 return resp
Fetch aggregated activity stats for a specific membership character.
Parameters
- character_id (
int): The character ID to return the stats for. - membership_id (
int): The Destiny membership id to return the stats for. - membership_type (
aiobungie.MembershipType | int): The Destiny membership type to return the stats for.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the aggregated activity stats.
2209 async def equip_loadout( 2210 self, 2211 access_token: str, 2212 /, 2213 loadout_index: int, 2214 character_id: int, 2215 membership_type: typedefs.IntAnd[enums.MembershipType], 2216 ) -> None: 2217 response = await self._request( 2218 RequestMethod.POST, 2219 "Destiny2/Actions/Loadouts/EquipLoadout/", 2220 json={ 2221 "loadoutIndex": loadout_index, 2222 "characterId": character_id, 2223 "membership_type": int(membership_type), 2224 }, 2225 auth=access_token, 2226 ) 2227 assert isinstance(response, int)
Equip a loadout. Your character must be in a Social space, Orbit or Offline while performing this operation.
This operation requires MoveEquipDestinyItems OAuth2 scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - loadout_index (
int): The index of the loadout to use. - character_id (
int): The character ID to equip the loadout to. - membership_type (
aiobungie.MembershipType | int): The membership type of the account.
2229 async def snapshot_loadout( 2230 self, 2231 access_token: str, 2232 /, 2233 loadout_index: int, 2234 character_id: int, 2235 membership_type: typedefs.IntAnd[enums.MembershipType], 2236 *, 2237 color_hash: typing.Optional[int] = None, 2238 icon_hash: typing.Optional[int] = None, 2239 name_hash: typing.Optional[int] = None, 2240 ) -> None: 2241 response = await self._request( 2242 RequestMethod.POST, 2243 "Destiny2/Actions/Loadouts/SnapshotLoadout/", 2244 auth=access_token, 2245 json={ 2246 "colorHash": color_hash, 2247 "iconHash": icon_hash, 2248 "nameHash": name_hash, 2249 "loadoutIndex": loadout_index, 2250 "characterId": character_id, 2251 "membershipType": int(membership_type), 2252 }, 2253 ) 2254 assert isinstance(response, int)
Snapshot a loadout with the currently equipped items.
This operation requires MoveEquipDestinyItems OAuth2 scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - loadout_index (
int): The index of the loadout to use. - character_id (
int): The character ID to equip the loadout to. - membership_type (
aiobungie.MembershipType | int): The membership type of the account.
Other Parameters
- color_hash (
int | None): ... - icon_hash (
int | None): ... - name_hash (
int | None): ...
2256 async def update_loadout( 2257 self, 2258 access_token: str, 2259 /, 2260 loadout_index: int, 2261 character_id: int, 2262 membership_type: typedefs.IntAnd[enums.MembershipType], 2263 *, 2264 color_hash: typing.Optional[int] = None, 2265 icon_hash: typing.Optional[int] = None, 2266 name_hash: typing.Optional[int] = None, 2267 ) -> None: 2268 response = await self._request( 2269 RequestMethod.POST, 2270 "Destiny2/Actions/Loadouts/UpdateLoadoutIdentifiers/", 2271 auth=access_token, 2272 json={ 2273 "colorHash": color_hash, 2274 "iconHash": icon_hash, 2275 "nameHash": name_hash, 2276 "loadoutIndex": loadout_index, 2277 "characterId": character_id, 2278 "membershipType": int(membership_type), 2279 }, 2280 ) 2281 assert isinstance(response, int)
Update the loadout. Color, Icon and Name.
This operation requires MoveEquipDestinyItems OAuth2 scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - loadout_index (
int): The index of the loadout to use. - character_id (
int): The character ID to equip the loadout to. - membership_type (
aiobungie.MembershipType | int): The membership type of the account.
Other Parameters
- color_hash (
int | None): The new color hash of the loadout to update. - icon_hash (
int | None): The new icon hash of the loadout to update. - name_hash (
int | None): The new name hash of the loadout to update.
2283 async def clear_loadout( 2284 self, 2285 access_token: str, 2286 /, 2287 loadout_index: int, 2288 character_id: int, 2289 membership_type: typedefs.IntAnd[enums.MembershipType], 2290 ) -> None: 2291 response = await self._request( 2292 RequestMethod.POST, 2293 "Destiny2/Actions/Loadouts/ClearLoadout/", 2294 json={ 2295 "loadoutIndex": loadout_index, 2296 "characterId": character_id, 2297 "membership_type": int(membership_type), 2298 }, 2299 auth=access_token, 2300 ) 2301 assert isinstance(response, int)
Clear the identifiers and items of a loadout.
This operation requires MoveEquipDestinyItems OAuth2 scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - loadout_index (
int): The index of the loadout to use. - character_id (
int): The character ID to equip the loadout to. - membership_type (
aiobungie.MembershipType | int): The membership type of the account.
195class RESTPool: 196 """Pool of `RESTClient` instances. 197 198 This allows to create multiple instances of `RESTClient`s that can be acquired 199 which share the same TCP connector. 200 201 Example 202 ------- 203 ```py 204 import aiobungie 205 206 client_pool = aiobungie.RESTPool("token", client_id=1234, client_secret='secret') 207 208 # Using a context manager to acquire an instance 209 # from the pool and close it after. 210 async with client_pool.acquire() as rest: 211 ... 212 ``` 213 214 Parameters 215 ---------- 216 token : `str` 217 A valid application token from Bungie's developer portal. 218 219 Other Parameters 220 ---------------- 221 max_retries : `int` 222 The max retries number to retry if the request hit a `5xx` status code. 223 client_secret : `typing.Optional[str]` 224 An optional application client secret, 225 This is only needed if you're fetching OAuth2 tokens with this client. 226 client_id : `typing.Optional[int]` 227 An optional application client id, 228 This is only needed if you're fetching OAuth2 tokens with this client. 229 enable_debugging : `bool | str` 230 Whether to enable logging responses or not. 231 232 Logging Levels 233 -------------- 234 * `False`: This will disable logging. 235 * `True`: This will set the level to `DEBUG` and enable logging minimal information. 236 Like the response status, route, taken time and so on. 237 * `"TRACE" | aiobungie.TRACE`: This will log the response headers along with the minimal information. 238 """ 239 240 __slots__ = ( 241 "_token", 242 "_max_retries", 243 "_client_secret", 244 "_client_id", 245 "_metadata", 246 "_enable_debug", 247 "_client_session", 248 "_loads", 249 "_dumps", 250 ) 251 252 # Looks like mypy doesn't like this. 253 if typing.TYPE_CHECKING: 254 _enable_debug: typing.Union[typing.Literal["TRACE"], bool, int] 255 256 def __init__( 257 self, 258 token: str, 259 /, 260 *, 261 client_secret: typing.Optional[str] = None, 262 client_id: typing.Optional[int] = None, 263 client_session: typing.Optional[aiohttp.ClientSession] = None, 264 dumps: typedefs.Dumps = helpers.dumps, 265 loads: typedefs.Loads = helpers.loads, 266 max_retries: int = 4, 267 enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False, 268 ) -> None: 269 self._client_secret = client_secret 270 self._client_id = client_id 271 self._token = token 272 self._max_retries = max_retries 273 self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {} 274 self._enable_debug = enable_debugging 275 self._client_session = client_session 276 self._loads = loads 277 self._dumps = dumps 278 279 @property 280 def client_id(self) -> typing.Optional[int]: 281 return self._client_id 282 283 @property 284 def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]: 285 """Pool's Metadata. This is different from client instance metadata.""" 286 return self._metadata 287 288 @typing.final 289 def acquire(self) -> RESTClient: 290 """Acquires a new `RESTClient` instance from this REST pool. 291 292 Returns 293 ------- 294 `RESTClient` 295 An instance of a REST client. 296 """ 297 return RESTClient( 298 self._token, 299 client_secret=self._client_secret, 300 client_id=self._client_id, 301 loads=self._loads, 302 dumps=self._dumps, 303 max_retries=self._max_retries, 304 enable_debugging=self._enable_debug, 305 client_session=self._client_session, 306 )
Pool of RESTClient instances.
This allows to create multiple instances of RESTClients that can be acquired
which share the same TCP connector.
Example
import aiobungie
client_pool = aiobungie.RESTPool("token", client_id=1234, client_secret='secret')
# Using a context manager to acquire an instance
# from the pool and close it after.
async with client_pool.acquire() as rest:
...
Parameters
- token (
str): A valid application token from Bungie's developer portal.
Other Parameters
- max_retries (
int): The max retries number to retry if the request hit a5xxstatus code. - client_secret (
typing.Optional[str]): An optional application client secret, This is only needed if you're fetching OAuth2 tokens with this client. - client_id (
typing.Optional[int]): An optional application client id, This is only needed if you're fetching OAuth2 tokens with this client. - enable_debugging (
bool | str): Whether to enable logging responses or not.
Logging Levels
False: This will disable logging.True: This will set the level toDEBUGand enable logging minimal information. Like the response status, route, taken time and so on."TRACE" | TRACE: This will log the response headers along with the minimal information.
256 def __init__( 257 self, 258 token: str, 259 /, 260 *, 261 client_secret: typing.Optional[str] = None, 262 client_id: typing.Optional[int] = None, 263 client_session: typing.Optional[aiohttp.ClientSession] = None, 264 dumps: typedefs.Dumps = helpers.dumps, 265 loads: typedefs.Loads = helpers.loads, 266 max_retries: int = 4, 267 enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False, 268 ) -> None: 269 self._client_secret = client_secret 270 self._client_id = client_id 271 self._token = token 272 self._max_retries = max_retries 273 self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {} 274 self._enable_debug = enable_debugging 275 self._client_session = client_session 276 self._loads = loads 277 self._dumps = dumps
Pool's Metadata. This is different from client instance metadata.
288 @typing.final 289 def acquire(self) -> RESTClient: 290 """Acquires a new `RESTClient` instance from this REST pool. 291 292 Returns 293 ------- 294 `RESTClient` 295 An instance of a REST client. 296 """ 297 return RESTClient( 298 self._token, 299 client_secret=self._client_secret, 300 client_id=self._client_id, 301 loads=self._loads, 302 dumps=self._dumps, 303 max_retries=self._max_retries, 304 enable_debugging=self._enable_debug, 305 client_session=self._client_session, 306 )
Acquires a new RESTClient instance from this REST pool.
Returns
RESTClient: An instance of a REST client.
485@typing.final 486class Race(int, Enum): 487 """An Enum for Destiny races.""" 488 489 HUMAN = 0 490 AWOKEN = 1 491 EXO = 2 492 UNKNOWN = 3
An Enum for Destiny races.
133@typing.final 134class Raid(int, Enum): 135 """An Enum for all available raids in Destiny 2.""" 136 137 DSC = 910380154 138 """Deep Stone Crypt""" 139 140 LW = 2122313384 141 """Last Wish""" 142 143 VOG = 3881495763 144 """Normal Valut of Glass""" 145 146 GOS = 3458480158 147 """Garden Of Salvation"""
An Enum for all available raids in Destiny 2.
252@attrs.define(auto_exc=True) 253class RateLimitedError(HTTPError): 254 """Raised when too many request status code is returned.""" 255 256 http_status: http.HTTPStatus = attrs.field( 257 default=http.HTTPStatus.TOO_MANY_REQUESTS, init=False 258 ) 259 """The request response http status.""" 260 261 url: typedefs.StrOrURL 262 """The URL/endpoint caused this error.""" 263 264 body: typing.Any 265 """The response body.""" 266 267 retry_after: float = attrs.field(default=0.0) 268 """The amount of seconds you need to wait before retrying to requests.""" 269 270 message: str = attrs.field(init=False) 271 """A Bungie human readable message describes the cause of the error.""" 272 273 @message.default # type: ignore 274 def _(self) -> str: 275 return f"You're ratelimited for {self.retry_after}, Endpoint: {self.url}. Slow down!" 276 277 def __str__(self) -> str: 278 return self.message
Raised when too many request status code is returned.
2def __init__(self, url, body, retry_after=attr_dict['retry_after'].default): 3 self.http_status = attr_dict['http_status'].default 4 self.url = url 5 self.body = body 6 self.retry_after = retry_after 7 self.message = __attr_factory_message(self) 8 BaseException.__init__(self, self.url,self.body,self.retry_after)
Method generated by attrs for class RateLimitedError.
Inherited Members
- builtins.BaseException
- with_traceback
- args
48@typing.final 49class RecordState(enums.Flag): 50 """An enum for records component states.""" 51 52 NONE = 0 53 REDEEMED = 1 << 0 54 UNAVAILABLE = 1 << 1 55 OBJECTIVE_NOT_COMPLETED = 1 << 2 56 OBSCURED = 1 << 3 57 INVISIBLE = 1 << 4 58 ENTITLEMENT_UNOWNED = 1 << 5 59 CAN_EQUIP_TITLE = 1 << 6
An enum for records component states.
680@typing.final 681class Relationship(int, Enum): 682 """An enum for bungie friends relationship types.""" 683 684 UNKNOWN = 0 685 FRIEND = 1 686 INCOMING_REQUEST = 2 687 OUTGOING_REQUEST = 3
An enum for bungie friends relationship types.
180class RequestMethod(str, enums.Enum): 181 """HTTP request methods enum.""" 182 183 GET = "GET" 184 """GET methods.""" 185 POST = "POST" 186 """POST methods.""" 187 PUT = "PUT" 188 """PUT methods.""" 189 PATCH = "PATCH" 190 """PATCH methods.""" 191 DELETE = "DELETE" 192 """DELETE methods"""
HTTP request methods enum.
Inherited Members
- builtins.str
- encode
- replace
- split
- rsplit
- join
- capitalize
- casefold
- title
- center
- count
- expandtabs
- find
- partition
- index
- ljust
- lower
- lstrip
- rfind
- rindex
- rjust
- rstrip
- rpartition
- splitlines
- strip
- swapcase
- translate
- upper
- startswith
- endswith
- removeprefix
- removesuffix
- isascii
- islower
- isupper
- istitle
- isspace
- isdecimal
- isdigit
- isnumeric
- isalpha
- isalnum
- isidentifier
- isprintable
- zfill
- format
- format_map
- maketrans
247@attrs.define(auto_exc=True) 248class ResponseError(HTTPException): 249 """Exception for other HTTP response errors."""
Exception for other HTTP response errors.
2def __init__(self, *, error_code, http_status, throttle_seconds, url, body, headers, message, error_status, message_data): 3 self.error_code = error_code 4 self.http_status = http_status 5 self.throttle_seconds = throttle_seconds 6 self.url = url 7 self.body = body 8 self.headers = headers 9 self.message = message 10 self.error_status = error_status 11 self.message_data = message_data 12 BaseException.__init__(self, self.error_code,self.http_status,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)
Method generated by attrs for class ResponseError.
Inherited Members
- HTTPException
- error_code
- http_status
- throttle_seconds
- url
- body
- headers
- message
- error_status
- message_data
- builtins.BaseException
- with_traceback
- args
507@typing.final 508class Stat(int, Enum): 509 """An Enum for Destiny 2 character stats.""" 510 511 NONE = 0 512 MOBILITY = 2996146975 513 RESILIENCE = 392767087 514 RECOVERY = 1943323491 515 DISCIPLINE = 1735777505 516 INTELLECT = 144602215 517 STRENGTH = 4244567218 518 LIGHT_POWER = 1935470627
An Enum for Destiny 2 character stats.
622@typing.final 623class TierType(int, Enum): 624 """An enum for a Destiny 2 item tier type.""" 625 626 UNKNOWN = 0 627 CURRENCY = 1 628 BASIC = 2 629 COMMON = 3 630 RARE = 4 631 SUPERIOR = 5 632 EXOTIC = 6
An enum for a Destiny 2 item tier type.
732@typing.final 733class TransferStatus(Flag): 734 """An enum for items transfer statuses.""" 735 736 CAN_TRANSFER = 0 737 """The item can be transferred.""" 738 IS_EQUIPPED = 1 << 0 739 """You can't transfer since the item is equipped.""" 740 NOT_TRASNFERRABLE = 1 << 1 741 """This item can not be transferred.""" 742 COULD_BE_TRANSFERRED = 1 << 2 743 """You can transfer the item. But the place you're trying to put it at has no space for it."""
An enum for items transfer statuses.
You can transfer the item. But the place you're trying to put it at has no space for it.
33class UndefinedType: 34 """An `UNDEFINED` type.""" 35 36 __instance: typing.Optional[UndefinedType] = None 37 38 def __bool__(self) -> typing.Literal[False]: 39 return False 40 41 def __int__(self) -> typing.Literal[0]: 42 return 0 43 44 def __repr__(self) -> str: 45 return "UNDEFINED" 46 47 def __str__(self) -> str: 48 return "UNDEFINED" 49 50 def __new__(cls) -> UndefinedType: 51 if cls.__instance is None: 52 o = super().__new__(cls) 53 cls.__instance = o 54 return cls.__instance
An UNDEFINED type.
75@typing.final 76class ValueUIStyle(int, enums.Enum): 77 AUTOMATIC = 0 78 FRACTION = 1 79 CHECK_BOX = 2 80 PERCENTAGE = 3 81 DATETIME = 4 82 FRACTION_FLOAT = 5 83 INTEGER = 6 84 TIME_DURATION = 7 85 HIDDEN = 8 86 MULTIPLIER = 9 87 GREEN_PIPS = 10 88 RED_PIPS = 11 89 EXPLICIT_PERCENTAGE = 12 90 RAW_FLOAT = 13 91 LEVEL_AND_REWARD = 14
An enumeration.
230@typing.final 231class Vendor(int, Enum): 232 """An Enum for all available vendors in Destiny 2.""" 233 234 ZAVALA = 69482069 235 XUR = 2190858386 236 BANSHE = 672118013 237 SPIDER = 863940356 238 SHAXX = 3603221665 239 KADI = 529635856 240 """Postmaster exo.""" 241 YUNA = 1796504621 242 """Asia servers only.""" 243 EVERVERSE = 3361454721 244 AMANDA = 460529231 245 """Amanda holiday""" 246 CROW = 3611983588 247 HAWTHORNE = 3347378076 248 ADA1 = 350061650 249 DRIFTER = 248695599 250 IKORA = 1976548992 251 SAINT = 765357505 252 """Saint-14""" 253 ERIS_MORN = 1616085565 254 SHAW_HAWN = 1816541247 255 """COSMODROME Guy""" 256 VARIKS = 2531198101
An Enum for all available vendors in Destiny 2.
521@typing.final 522class WeaponType(int, Enum): 523 """Enums for The three Destiny Weapon Types""" 524 525 NONE = 0 526 KINETIC = 1498876634 527 ENERGY = 2465295065 528 POWER = 953998645
Enums for The three Destiny Weapon Types
574def iter( 575 iterable: collections.Iterable[Item], 576) -> Iterator[Item]: 577 """Transform an iterable into an flat iterator. 578 579 Example 580 ------- 581 ```py 582 sequence = [1,2,3] 583 for item in aiobungie.iter(sequence).reversed(): 584 print(item) 585 # 3 586 # 2 587 # 1 588 ``` 589 590 Parameters 591 ---------- 592 iterable: `typing.Iterable[Item]` 593 The iterable to convert. 594 595 Raises 596 ------ 597 `StopIteration` 598 If no elements are left in the iterator. 599 """ 600 return Iterator(iterable)
Transform an iterable into an flat iterator.
Example
sequence = [1,2,3]
for item in aiobungie.iter(sequence).reversed():
print(item)
# 3
# 2
# 1
Parameters
- iterable (
typing.Iterable[Item]): The iterable to convert.
Raises
StopIteration: If no elements are left in the iterator.
281async def raise_error(response: aiohttp.ClientResponse) -> AiobungieError: 282 """Generates and raise exceptions on error responses.""" 283 284 # Not a JSON response, raise immediately. 285 286 # Also Bungie sometimes get funky and return HTML instead of JSON when making an authorized 287 # request with a dummy access token. I can't really do anything about this.. 288 if response.content_type != "application/json": 289 return HTTPError( 290 f"Expected JSON content but got {response.content_type!s}, {response.real_url!s}", 291 http.HTTPStatus.UNSUPPORTED_MEDIA_TYPE, 292 ) 293 294 body = await response.json() 295 message: str = body.get("Message", "UNDEFINED_MESSAGE") 296 error_status: str = body.get("ErrorStatus", "UNDEFINED_ERROR_STATUS") 297 message_data: dict[str, str] = body.get("MessageData", {}) 298 throttle_seconds: int = body.get("ThrottleSeconds", 0) 299 error_code: int = body.get("ErrorCode", 0) 300 301 # Standard HTTP status. 302 if response.status == http.HTTPStatus.NOT_FOUND: 303 return NotFound( 304 message=message, 305 error_code=error_code, 306 throttle_seconds=throttle_seconds, 307 url=str(response.real_url), 308 body=body, 309 headers=response.headers, 310 error_status=error_status, 311 message_data=message_data, 312 ) 313 314 elif response.status == http.HTTPStatus.FORBIDDEN: 315 return Forbidden( 316 message=message, 317 error_code=error_code, 318 throttle_seconds=throttle_seconds, 319 url=str(response.real_url), 320 body=body, 321 headers=response.headers, 322 error_status=error_status, 323 message_data=message_data, 324 ) 325 326 elif response.status == http.HTTPStatus.UNAUTHORIZED: 327 return Unauthorized( 328 message=message, 329 error_code=error_code, 330 throttle_seconds=throttle_seconds, 331 url=str(response.real_url), 332 body=body, 333 headers=response.headers, 334 error_status=error_status, 335 message_data=message_data, 336 ) 337 338 elif response.status == http.HTTPStatus.BAD_REQUEST: 339 # Membership needs to be alone. 340 if error_status == "InvalidParameters": 341 return MembershipTypeError( 342 message=message, 343 body=body, 344 headers=response.headers, 345 url=str(response.url), 346 membership_type=message_data["membershipType"], 347 required_membership=message_data["membershipInfo.membershipType"], 348 membership_id=int(message_data["membershipId"]), 349 ) 350 return BadRequest( 351 message=message, 352 body=body, 353 headers=response.headers, 354 url=str(response.url), 355 ) 356 357 status = http.HTTPStatus(response.status) 358 359 if 400 <= status < 500: 360 return ResponseError( 361 message=message, 362 error_code=error_code, 363 throttle_seconds=throttle_seconds, 364 url=str(response.real_url), 365 body=body, 366 headers=response.headers, 367 error_status=error_status, 368 message_data=message_data, 369 http_status=status, 370 ) 371 372 # Need to self handle ~5xx errors 373 elif 500 <= status < 600: 374 # No API key or method requires OAuth2 most likely. 375 if error_status in { 376 "ApiKeyMissingFromRequest", 377 "WebAuthRequired", 378 "ApiInvalidOrExpiredKey", 379 "AuthenticationInvalid", 380 "AuthorizationCodeInvalid", 381 }: 382 return Unauthorized( 383 message=message, 384 error_code=error_code, 385 throttle_seconds=throttle_seconds, 386 url=str(response.real_url), 387 body=body, 388 headers=response.headers, 389 error_status=error_status, 390 message_data=message_data, 391 ) 392 393 # Anything contains not found. 394 elif ( 395 "NotFound" in error_status or error_status == "UserCannotFindRequestedUser" 396 ): 397 return NotFound( 398 message=message, 399 error_code=error_code, 400 throttle_seconds=throttle_seconds, 401 url=str(response.real_url), 402 body=body, 403 headers=response.headers, 404 error_status=error_status, 405 message_data=message_data, 406 ) 407 408 # Other 5xx errors. 409 else: 410 return InternalServerError( 411 message=message, 412 error_code=error_code, 413 throttle_seconds=throttle_seconds, 414 url=str(response.real_url), 415 body=body, 416 headers=response.headers, 417 error_status=error_status, 418 message_data=message_data, 419 http_status=status, 420 ) 421 # Something else. 422 else: 423 return HTTPException( 424 message=message, 425 error_code=error_code, 426 throttle_seconds=throttle_seconds, 427 url=str(response.real_url), 428 body=body, 429 headers=response.headers, 430 error_status=error_status, 431 message_data=message_data, 432 http_status=status, 433 )
Generates and raise exceptions on error responses.
436def stringify_http_message(headers: collections.Mapping[str, str]) -> str: 437 return ( 438 "{ \n" 439 + "\n".join( # noqa: W503 440 f"{f' {key}'}: {value}" 441 if key not in ("Authorization", "X-API-KEY") 442 else f" {key}: HIDDEN_TOKEN" 443 for key, value in headers.items() 444 ) 445 + "\n}" # noqa: W503 446 )